前言
本篇文章主要介绍如何创建、发送和接收HTTP请求和响应。
创建CFHTTP请求
HTTP请求实际上是包含了请求方法、URL、消息头和消息体的消息。请求方法通常是GET, HEAD, PUT, POST, DELETE, TRACE, CONNECT 或 OPTIONS。用CFHTTP创建HTTP请求需要四个步骤:
1.调用
CFHTTPMessageCreateRequest
方法生成CFHTTP消息对象。
2.调用CFHTTPMessageSetBody
方法设置消息体。
3.调用CFHTTPMessageSetHeaderFieldValue
方法设置消息头。
4.调用CFHTTPMessageCopySerializedMessage
方法对消息进行序列化。
|
|
在上面这段代码中,url会被CFURLCreateWithString
方法转换成CFURL对象。然后,调用CFHTTPMessageCreateRequest
创建HTTP请求对象。之后,将创建的对象连同消息体(bodyData)传入CFHTTPMessageSetBody
方法中,将请求对象连同消息头的名字(headerField)和值(value)传入CFHTTPMessageSetHeaderFieldValue
方法中,headerField参数接受CFString类型的对象如Content-Length,value参数接受CFString类型的对象如1260。最后,调用CFHTTPMessageCopySerializedMessage
方法对消息进行序列化并且通过写入流发送到接受者那里。
当请求不再需要时,我们需要释放消息对象和序列化的消息。
|
|
创建CFHTTP响应
创建HTTP响应的步骤与创建HTTP请求的步骤是一致的。唯一的区别在于是调用CFHTTPMessageCreateResponse
方法而不是CFHTTPMessageCreateRequest
方法。
反序列化HTTP请求
要对收到的HTTP请求进行反序列化操作,首先要调用CFHTTPMessageCreateEmpty
方法创建空的消息对象,并在isRequest参数中传入true表示创建的是请求消息对象。然后,调用CFHTTPMessageAppendBytes
方法将接收到的HTTP请求添加到消息对象中去。CFHTTPMessageAppendBytes
方法会反序列化消息并且移除它保存的任何控制信息。一直不停地循环去调用该方法直到CFHTTPMessageIsHeaderComplete
返回true。若CFHTTPMessageIsHeaderComplete
没有返回true,说明消息是不完整的。
|
|
在CFHTTPMessageAppendBytes
方法中,data参数表示要被添加进消息对象中的数据,numBytes参数表示data的大小。你可以调用CFHTTPMessageIsHeaderComplete
方法去验证添加消息是否完成。
当消息反序列化完成后,你可以调用下面的方法从消息对象中截取信息:
CFHTTPMessageCopyBody
:获取消息体的拷贝CFHTTPMessageCopyHeaderFieldValue
:获取指定头部区域的拷贝CFHTTPMessageCopyAllHeaderFields
:获取所有消息头的拷贝CFHTTPMessageCopyRequestURL
:获取消息的URL的拷贝CFHTTPMessageCopyRequestMethod
:获取消息请求方法的拷贝
当你不在需要消息对象时,需要正确地对其进行释放和销毁操作。
反序列化HTTP响应
正如创建HTTP请求和创建HTTP响应很相似,反序列化HTTP请求和反序列化HTTP响应也非常相似。唯一重要的区别在于当调用CFHTTPMessageCreateEmpty
方法时,你必须给isRequest参数传入false表示创建的消息是响应消息。
使用读流序列化和发送HTTP请求
你可以使用CFReadStream对象序列化和发送CFHTTP请求。当你使用CFReadStream对象发送CFHTTP请求时,打开流会让消息的序列化和发送在一步中完成。使用CFReadStream对象发送CFHTTP请求让获取响应变得容易因为响应会作为流的属性而被访问。
序列化和发送HTTP请求
要使用CFReadStream对象序列化和发送HTTP请求,首先要创建CFHTTP请求并设置消息头和消息体。然后,调用CFReadStreamCreateForHTTPRequest
方法创建CFReadStream对象并传入先前创建的请求。最后,调用CFReadStreamOpen
打开读流。
当CFReadStreamCreateForHTTPRequest
方法被调用时,它会将传入的CFHTTP请求对象进行拷贝。因而,如果必要,你应该在调用完CFReadStreamCreateForHTTPRequest
方法后立即释放CFHTTP请求对象。因为读流要与指定的服务器建立套接字连接,所以在流可以打开之前需要耗费一部分时间。打开读流同样会引起请求的序列化和发送操作。
|
|
检查响应
在你将请求添加到runloop中后,你最终会得到完整的头部回调。这时候,你可以调用CFReadStreamCopyProperty
方法从读流中获取消息的响应。
|
|
你可以调用CFHTTPMessageCopyResponseStatusLine
方法从响应消息中得到状态行。
|
|
或者,调用CFHTTPMessageGetResponseStatusCode
方法得到响应消息的状态码。
|
|
处理认证错误
如果CFHTTPMessageGetResponseStatusCode
方法返回的状态码是401(远程服务器要求认证信息)或407(代理服务器要求认证),你需要将认证信息添加到请求中并重新发送。
处理重定向错误
当调用CFReadStreamCreateForHTTPRequest
方法创建读流,默认情况下流的自动重定向是被禁用的。如果请求指向的URL被重定向给另一个URL,你需要关闭流并重新创建流,打开流的重定向选项,最后打开流。
|
|
取消正在发送的请求
一旦请求发送出去后,就不可能阻止远程服务器对其进行操作。然而,如果你不再关心响应数据,你可以关闭流。注意,当另一个线程在同一个流中等待数据时不要从任何线程中关闭流。如果你需要终结请求,你需要使用不阻塞的方式(参见CFNetwork学习笔记(二))。在关闭流之前要确保将流从runloop中移除。