原文地址:developer
时间过的很快,一眨眼周末就过了。人的一生到底怎么样才能过的有意义呢?我一直在找答案。做自己喜欢的事情,爱自己喜欢的人,或是成就一番伟业。都是不错的选择,找到自己想要做的事情,不要放弃寻找。最终生命带走的只能是珍贵的回忆,晚上快乐。
与HTTP服务器通信
本章解释了如何创建、发送和接收HTTP请求和响应。
创建一个CFHTTP请求
组成一个HTTP请求消息的远程服务器执行的方法,对象操作(URL),消息头和消息体。方法通常是下列之一:GET,
HEAD, PUT, POST, DELETE, TRACE, CONNECT or OPTIONS。创建一个HTTP请求与CFHTTP需要四个步骤:
1.使用CFHTTPMessageCreateRequest函数生成一个CFHTTP消息对象。
2.使用函数CFHTTPMessageSetBody设置消息的主体。
3.设置消息的标题使用CFHTTPMessageSetHeaderFieldValue函数。
4.CFHTTPMessageCopySerializedMessage通过调用函数序列化消息。
示例代码看起来就像清单3中的代码。
CFStringRef bodyString = CFSTR(""); // Usually used for POST data
CFDataRef bodyData = CFStringCreateExternalRepresentation(kCFAllocatorDefault,
bodyString, kCFStringEncodingUTF8, 0);
CFStringRef headerFieldName = CFSTR("X-My-Favorite-Field");
CFStringRef headerFieldValue = CFSTR("Dreams");
CFStringRef url = CFSTR("http://www.apple.com");
CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, url, NULL);
CFStringRef requestMethod = CFSTR("GET");
CFHTTPMessageRef myRequest =
CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, myURL,
kCFHTTPVersion1_1);
CFDataRef bodyDataExt = CFStringCreateExternalRepresentation(kCFAllocatorDefault, bodyData, kCFStringEncodingUTF8, 0);
CFHTTPMessageSetBody(myRequest, bodyDataExt);
CFHTTPMessageSetHeaderFieldValue(myRequest, headerFieldName, headerFieldValue);
CFDataRef mySerializedRequest = CFHTTPMessageCopySerializedMessage(myRequest);
这个示例代码,url是通过调用CFURLCreateWithString首先转换成一个CFURL对象。然后用四个参数:CFHTTPMessageCreateRequest叫做kCFAllocatorDefault指定默认的系统内存分配器是用于创建消息引用,requestMethod指定方法,如POST方法,myURL指定URL,如http://www.apple.com,kCFHTTPVersion1_1指定消息的HTTP版本是1.1。
返回的消息对象引用(myRequest)CFHTTPMessageCreateRequest然后送到CFHTTPMessageSetBody随着消息的主体(bodyData)。然后调用CFHTTPMessageSetHeaderFieldValue使用相同的消息对象引用的名字一起头(headerField)和价值(价值)。头参数是CFString对象等内容长度,和值参数是CFString对象如1260。最后,通过调用CFHTTPMessageCopySerializedMessage消息序列化,应该通过写流发送到接收者,在这个例子中http://www.apple.com。
注意:请求主体通常省略。主要将使用请求主体是一个POST请求包含POST数据。它也可以用于其他WebDAV等有关HTTP请求类型的扩展。有关更多信息,请参见RFC
2616
当消息不再需要时,释放消息序列化对象和消息。参见清单3的示例代码
CFRelease(myRequest);
CFRelease(myURL);
CFRelease(url);
CFRelease(mySerializedRequest);
myRequest = NULL;
mySerializedRequest = NULL;
创建一个CFHTTP响应
创建一个HTTP响应几乎完全相同的步骤创建一个HTTP请求。唯一的区别是,而不是调用CFHTTPMessageCreateRequest,你调用函数CFHTTPMessageCreateResponse使用相同的参数。
反序列化传入的HTTP请求
反序列化传入的HTTP请求,创建一个空的消息使用CFHTTPMessageCreateEmpty函数,传递真实的isRequest参数指定要创建一个空的请求消息。然后使用函数CFHTTPMessageAppendBytes将传入消息添加到空的请求消息里。CFHTTPMessageAppendBytes反序列化消息并移除任何可能包含的控制信息。
继续这样做,直到函数CFHTTPMessageIsHeaderComplete返回TRUE。如果你不检查CFHTTPMessageIsHeaderComplete返回TRUE,消息可能是不完整的和不可靠的。一个示例使用清单3
- 3中可以看到这两个函数。
CFHTTPMessageRef myMessage = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE);
if (!CFHTTPMessageAppendBytes(myMessage, &data, numBytes)) {
//Handle parsing error
}
在这个示例中,数据是附加的数据和numBytes数据的长度。你可能想叫CFHTTPMessageIsHeaderComplete附加消息的验证头就完成了。
if (CFHTTPMessageIsHeaderComplete(myMessage)) {
// Perform processing.
}
反序列化的消息,您现在可以从以下函数提取信息:
1.CFHTTPMessageCopyBody消息正文的一个副本
2.CFHTTPMessageCopyHeaderFieldValue获得特定的header字段值的副本
3.CFHTTPMessageCopyAllHeaderFields拿到一份所有消息的头字段
4.CFHTTPMessageCopyRequestURL的消息副本的URL
5.CFHTTPMessageCopyRequestMethod得到消息的请求方法的副本
当你不再需要信息,就释放,正确的处理它。
反序列化传入的HTTP响应
就像创建一个HTTP请求非常类似于创建一个HTTP响应,反序列化传入HTTP请求也非常类似于反序列化传入的HTTP响应。唯一重要的区别是,当调用CFHTTPMessageCreateEmpty,你必须通过isRequest参数指定要创建的消息是一个响应消息
使用读取流序列化并发送HTTP请求
您可以使用一个CFReadStream对象序列化和发送CFHTTP请求。当你使用CFReadStream CFHTTP请求对象发送,打开流导致消息序列化和发送在一个步骤。使用CFReadStream对象发送CFHTTP请求让我们更加容易的请求的响应,因为响应是可用属性的流。
序列化并发送一个HTTP请求
使用CFReadStream对象序列化并发送一个HTTP请求,首先创建一个CFHTTP请求和设置消息正文和标题中描述创建一个CFHTTP请求。然后创建一个CFReadStream对象通过调用函数CFReadStreamCreateForHTTPRequest和通过请求您刚刚创建的。最后,用CFReadStreamOpen打开读取流。
当CFReadStreamCreateForHTTPRequest被调用时,它通过CFHTTP复制请求对象。因此,如果有必要,你可以调用CFReadStreamCreateForHTTPRequest后立即释放CFHTTP请求对象。
因为读流与服务器打开一个套接字连接指定的myUrl参数CFHTTP请求创建时,一段时间前必须允许通过流被认为是开放的。打开读取流也让请求序列化和发送。
如何序列化和发送一个HTTP请求可以看清单3 - 4所示。
CFStringRef url = CFSTR("http://www.apple.com");
CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, url, NULL);
CFStringRef requestMethod = CFSTR("GET");
CFHTTPMessageRef myRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
requestMethod, myUrl, kCFHTTPVersion1_1);
CFHTTPMessageSetBody(myRequest, bodyData);
CFHTTPMessageSetHeaderFieldValue(myRequest, headerField, value);
CFReadStreamRef myReadStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, myRequest);
CFReadStreamOpen(myReadStream);
检查响应
调度的请求run loop之后,你最终会得到一个头完成回调。在这一点上,你可以叫CFReadStreamCopyProperty阅读得到的消息响应流
CFHTTPMessageRef myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader);
你可以得到完整的状态行CFHTTPMessageCopyResponseStatusLine响应消息通过调用函数:
CFStringRef myStatusLine = CFHTTPMessageCopyResponseStatusLine(myResponse);
或者只是响应消息的状态代码CFHTTPMessageGetResponseStatusCode通过调用函数
UInt32 myErrCode = CFHTTPMessageGetResponseStatusCode(myResponse);
注意:如果您正在使用这个类同步(没有调用run loop),你必须开始阅读消息通过至少一个调用CFReadStreamRead调用CFReadStreamCopyProperty之前。CFReadStreamRead调用直到数据块(或连接失败)是可用的。不要在你的主应用程序线程上做这个。
处理身份验证错误
如果返回的状态码函数CFHTTPMessageGetResponseStatusCode是401(远程服务器需要身份验证信息)或407(代理服务器需要身份验证),您需要将身份验证信息附加到请求和发送一遍。请阅读
Communicating with Authenticating HTTP Servers 如何处理身份验证。
处理重定向错误
当CFReadStreamCreateForHTTPRequest创建一个读流,自动重定向流默认情况下是禁用的。如果统一资源定位符,或者URL,该URL发送请求重定向到另一个,发送请求将导致一个错误的状态码300到307不等。如果你收到一个重定向错误,你需要关闭流,创建流再次启用自动重定向,并打开流。参见清单3
- 5
CFReadStreamClose(myReadStream);
CFReadStreamRef myReadStream =
CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, myRequest);
if (CFReadStreamSetProperty(myReadStream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue) == false) {
// something went wrong, exit
}
CFReadStreamOpen(myReadStream);
你当你创建一个读取流可能想要启用自动重定向。
取消一个未决请求
一旦请求已经发送,它是不可能阻止远程服务器代理。然而,如果你不再关心响应数据,您可以关闭流。
重要:不要从任何线程关闭流,另一个线程正在等待该流的内容。如果你需要能够终止请求时,您应该使用非阻塞I / O防止所述阻塞在处理流。一定要run
loop关闭之前删除流。
版权声明:本文为博主原创文章,未经博主允许不得转载。