SCHTTPClient 1.0.1

SCHTTPClient 1.0.1

Matt Reach 维护。



  • debugly

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的客户端仍会报告上传进度(即使我知道套接字已被关闭),并最终因为“请求超时”而失败,而不是服务器通过管道发送的响应。

这意味着:

  1. NSURLConnection在发送请求正文之前没有等待100-Continue代理响应;
  2. NSURLConnection没有意识到已经发送了响应并且连接正在结束,直到它上传了它必须要上传的内容。真是个顽固的家伙啊!

我曾经提交了一个错误报告,但在等待了一年后,我决定提出一个可行的替代方案。巧合的是,在我把这个库公开的同一天,我收到了苹果的回复——把这个错误标记为其他我不具备访问权限的问题的重复。

通过对curl的命令行版本的快速测试,证明了curl知道如何正确处理这些边缘情况,所以是时候为Cocoa构建一个新的HTTP框架了。

在这个过程中,产生了这个实用的构建脚本,即使你不想使用这个库,但仍然对在iOS上运行curl感兴趣,也请查看一下!

依赖项

  • libcurl(见下文)
  • libz.dylib
  • Security框架
  • CoreServices框架在OSX上,MobileCoreServices框架在iOS上
  • AppKit框架在OSX上,UIKit框架在iOS上

注意:您可以在Build/iOS/Static lib/libcurlBuild/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。我也会偶尔写作。