SCHTTPClient
SCHTTPClient 基于 BBHTTP,这是用 Objective-C 编写的对 libcurl 进行丰富包装的库。
它是一个仅支持 ARC 的库,使用了 Clang 3.1 引入的 功能。因此,它仅适用于 iOS 5+ 和 OSX 10.7+。
它提供了一个极简单且紧凑的接口,允许您将发送 HTTP 请求的代码缩减为几行清晰的代码,而在需要时仍然保持全部灵活性。
[[SCHTTPRequest readResource:@"http://foo.bar/baz"] execute:^(SCHTTPResponse* r) {
NSLog(@"Finished: %u %@ -- received %u bytes of '%@'.",
r.code, r.message, r.contentSize, r[@"Content-Type"]);
} error:^(NSError* e) {
NSLog(@"Request failed: %@", [e localizedDescription]);
}];
// Finished: 200 OK -- received 68364 bytes of 'text/html'.
目前还有很多粗糙的边缘需要打磨,需要修复的错误和需要实现的功能才能与其他类似项目相提并论。我打算逐步添加这些功能,但总是欢迎帮助,所以请务必为您希望看到的功能打开问题,或在 Twitter 上提及我 @biasedbit。
API 很可能在此达到 1.0 之前不断变化。
亮点
-
简洁的异步驱动使用
[[SCHTTPRequest deleteResource:@"http://foo.bar/baz/1"] execute:^(SCHTTPResponse* r) { // handle response } error:nil]];
您甚至不需要保留请求的引用,只需运行并忘记。
-
方便的常用模式
[[SCHTTPRequest readResource:@"http://foo.bar/baz/1"] setup:^(id request) { // Prepare request... } execute:^(SCHTTPResponse* response) { // Handle response... } error:^(NSError* error) { // Handle error... } finally:^{ // Do after error OR success. }];
-
轻松获取 JSON
[[[SCHTTPRequest readResource:@"http://foo.bar/baz.json"] asJSON] execute:^(SCHTTPResponse* r) { NSLog(@"User email: %@", r.content[@"user.email"]); NSLog(@"# of followers: %@", r.content[@"user.followers.@count"]); } error:^(NSError* error) { // Handle request *or* JSON decoding error }];
注意键索引操作符的行为类似于
valueForKeyPath:
而不是valueForKey:
。这是因为会产生NSDictionary
的 JSON 响应将包装在SCJSONDictionary
中。有关集合运算符的更多信息,请参阅此处。 -
也可以用图像
[[SCHTTPRequest readResource:@"http://foo.bar/baz.png"] setup:^(id request) { [request downloadContentAsImage]; } execute:^(SCHTTPResponse* response) { UIImage* image = response.content; // NSImage on OSX NSLog(@"image size: %@", NSStringFromCGSize(image.size)); } error:nil];
此示例在
setup
块上使用了downloadContentAsImage
来设置图像下载和转换,但您也可以使用像上面的 JSON 示例一样流畅的语法替代选项(asImage
)。 -
从
NSInputStream
或直接从文件进行流式上传[[SCHTTPRequest createResource:@"http://foo.bar/baz" withContentsOfFile:@"/path/to/file"] setup:^(SCHTTPRequest* request) { request[@"Extra-Header"] = @"something else"; } execute:^(SCHTTPResponse* response) { // handle response } error:nil];
请求的内容类型和内容长度标头将根据文件的属性自动设置。
-
下载到内存缓冲区或直接流到文件/
NSOutputStream
[[SCHTTPRequest readResource:@"http://foo.bar/baz"] setup:^(SCHTTPRequest* request) { [request downloadToFile:@"/path/to/file"]; } execute:^(SCHTTPResponse* response) { // handle response } error:nil];
下载中途失败时无需删除文件;SCHTTP会负责保持一切整洁。
-
当您需要更多控制时,有一个power-dev API。
SCHTTPExecutor* twitterExecutor = [SCHTTPExecutor initWithId:@"twitter.com"]; SCHTTPExecutor* facebookExecutor = [SCHTTPExecutor initWithId:@"facebook.com"]; twitterExecutor.maxParallelRequests = 10; facebookExecutor.maxParallelRequests = 2; ... SCHTTPRequest* request = [[SCHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://twitter.com/resource"] andVerb:@"GET"]; request[@"Accept-Language"] = @"en-us"; request.downloadProgressBlock = ^(NSUInteger current, NSUInteger total) { /* ... */ }; request.finishBlock = ^(SCHTTPRequest* request) { /* ... */ }; [twitterExecutor executeRequest:request];
还有其他内置方式来处理响应内容。请确保阅读有关响应内容处理的详细指南。
文档
可能的待办事项列表
- 多部分上传助手
- 跟随重定向
- 使用curl的multi handles
- 您的明亮想法在这里
要获取完整列表,请务必访问路线图wiki页面。
为什么?
难道不是因为它简洁的API或者它实际上使用libcurl吗?
嗯,与NSURLConnection
以及依赖它的任何库不同,SCHTTP...
- 严格遵守RFC 2616的第8.2.3节,也称为讨厌的
Expect: 100-Continue
头; - 可以在上传过程中接收服务器错误响应——而不是继续向socket eden泵送数据,最终报告连接超时而不是服务器实际发送的实际错误响应。
“但我的上传工作得很正常……”
- 如果您只编写了上传到服务器的代码,您可能从未注意到上述任一问题;
- 如果您编写了客户端和服务器端代码来处理上传,那么您可能从未遇到过上述任一问题;
- 如果您是 hardcore 级别,并编写了自己的服务器和客户端,并注意到
NSURLConnection
直到完成上传才会忽略错误,那么这就是您需要的HTTP框架。并且为编写自己的服务器和客户端以及关注规范表示赞。
在更为严肃的语气中,这个libcurl包装器动机源于在开发Droplr的API服务器期间,我们注意到每当API拒绝上传并立即关闭连接时——这是一个完全合法和合理的行为——基于Cocoa的客户端仍会报告上传进度(即使我知道套接字已被关闭),并最终因为“请求超时”而失败,而不是服务器通过管道发送的响应。
这意味着:
NSURLConnection
在发送请求正文之前没有等待100-Continue
代理响应;NSURLConnection
没有意识到已经发送了响应并且连接正在结束,直到它上传了它必须要上传的内容。真是个顽固的家伙啊!
我曾经提交了一个错误报告,但在等待了一年后,我决定提出一个可行的替代方案。巧合的是,在我把这个库公开的同一天,我收到了苹果的回复——把这个错误标记为其他我不具备访问权限的问题的重复。
通过对curl的命令行版本的快速测试,证明了curl知道如何正确处理这些边缘情况,所以是时候为Cocoa构建一个新的HTTP框架了。
在这个过程中,产生了这个实用的构建脚本,即使你不想使用这个库,但仍然对在iOS上运行curl感兴趣,也请查看一下!
依赖项
libcurl
(见下文)libz.dylib
Security框架
CoreServices框架
在OSX上,MobileCoreServices框架
在iOS上AppKit框架
在OSX上,UIKit框架
在iOS上
注意:您可以在
Build/iOS/Static lib/libcurl
和Build/OSX/Static lib/libcurl
下找到libcurl 7.30.0的二进制文件和头文件。iOS有两个版本,编译针对6.1 SDK。libcurl.iOS.dev.a
支持i386(模拟器)、armv7和armv7s(iPhone 3GS及更新版)而libcurl.iOS.appstore.a
仅支持arm架构——使其体积更小,因此针对发布版本进行了优化。OSX版本编译针对10.8 SDK,支持x86_64(64位Intel)。如果您想构建自己的自定义版本,请尝试这个。所有二进制文件都编译了调试符号,因此尽管它们看起来很大,但最终大小为400~600KB。
文档
有关如何设置和开始使用这个库的指南,请参阅wiki页面。
项目还包括全面的类级别文档。如果您已安装appledoc,只需在Docs
文件夹上运行generate
脚本,它将在Docs/html
下为您生成html文档。
致谢
- Stenberg Daniel 及所有参与 cURL 和 libcurl 开发的人员
- Zitzmann Nick 为安全传输 TLS/SSL cURL 插件
- Ben Copsey 为 ASIHTTPRequest,自 iOS 诞生以来一直是我的 HTTP 工作马
许可证
SCHTTP 使用 Apache 软件许可证版本 2.0
联系方式
我推特上的 ID 为 @biasedbit。我也会偶尔写作。