阅读 1208

YMHTTP - 基于 libcurl 的 HTTP 框架

简介

YMHTTP 是一个适用于 iOS 平台,基于 libcurl 的 IO 多路复用 HTTP 框架。

其 API 设计和行为与 NSURLSession 保持高度一致,不仅可以省去学习成本还可以减少接入成本,同时也拓展了 DNS 的能力(包括 SNI 的场景)。

目前项目 UT 覆盖率 80% 左右,覆盖绝大多数 Case。

如果您有 DNS 方面的需求,那么 YMHTTP 绝对是一把利器,无论是使用价值还是参考价值,我想它在一定程度上可以帮到您。如果您没有 DNS 方面的需求,那么您可能暂时不需要它。

项目地址github.com/zymxxxs/YMH…

请点击项目地址阅读更多的内容。

为什么要写这么一个网络库

做过 DNS 相关事情的同学都会面临这些问题:

  • NSURLSessionNSURLConnection 无法支持 SNI 场景
  • CFNetwork 无法连接复用
  • SSL/TLS 握手不成功相关证书问题
  • 使用 CFNetwork 或者 libcurl 之后 Cache、Cookie、302 等问题

上述的这些问题,如果只在游历在上层,那么最后只会是一个在性能、成本等多个因素间相互妥协的结果。

性能、HTTP Cache、Cookie、302、SSL/TLS 等问题,想要比较好的解决问题还是需要更加 彻底 才行。

  • C 或 C++ 自己实现网络编程
  • 使用 C 版本的网络库 libcurl
  • 使用 Chromium 中的 cronet 网络层。

以上是我目前所了解到一些公司内部或者技术博客比较推荐的解法,其实它们的核心只有一点,要使用更底层的能力 来解决问题,实现成本从上到下依次递减,其中 libcurl 是一个 C 版本的网络库,需要自己去封装 OC 的接口,实现 HTTP Cache,Cookie 的逻辑,cronet 作为 Chromium 的网络层,采用 C++ 实现,其很贴心的封装了 Java 接口,但是 OC 的接口还是自己去封装,如果需要在 Android 和 iOS 上保持网络行为的一致性,cronet 也是一个比较好的选择,当然,Android 平台还有 okhttp 等其他选择。(泪目)

YMHTTP 则是选择 libcurl 进行封装,对外提供 OC 的接口,也支持 Cache、Cookies、Redirect等能力,其 API 与 NSURLSeesion 基本保持一致。它采用单线程 IO 多路复用有效的避免了多线程的上下文切换、创建/销毁带来的损耗,也可以保证其 '并发性能',这也是 libcurl 推荐的方式,您可以点击这里去查阅 MULTI_SOCKET 部分。

如果你想了解更多关于 DNS 的问题,请点击下方链接查看:

如何使用

  1. 您可以通过 NSURLSession 来查阅具体的细节。
  2. 这里有一份非常不错的NSURLSession最全攻略可以查漏补缺(来自搜狐技术产品)。
  3. YMHTTP 和 NSURLSession 非常像,一个是 YM 前缀,一个是 NS 前缀,对外提供的API基本一致。
  4. 这里只会介绍一下 IP 直连的相关用法,您可以前往 Github 了解更多详情

IP 直连

- (YMURLSessionTask *)taskWithURL:(NSURL *)url connectToHost:(NSString *)host;

- (YMURLSessionTask *)taskWithURL:(NSURL *)url connectToHost:(NSString *)host connectToPort:(NSInteger)port;

// 创建包含 host port 的 request
[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://httpbin.org/get"] connectToHost:@"52.202.2.199"];
[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://httpbin.org/get"] connectToHost:@"52.202.2.199" connectToPort:443];
[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://httpbin.org/get"]
                           connectToHost:@"52.202.2.199"
                           connectToPort:443
                             cachePolicy:NSURLRequestUseProtocolCachePolicy
                         timeoutInterval:60];
- (YMURLSessionTask *)taskWithRequest:(NSURLRequest *)request
复制代码

从代码来看,接口的调用还是比较简单的,不过您还需要调用某云提供的SDK完成 域名 -> IP的逻辑。

连接到特定的主机和端口,其中 host 支持 IP 的形式。如果使用 域名+host+port(可忽略) 的请求方式,那么对于框架内部可以自动处理 Cookie,Cache 以及 302 等问题。

备注:该接口不会影响到 DNS Cache,了解更多可以看这里 curl.haxx.se/libcurl/c/C…

HTTP/2

理论上 YMHTTP 是可以支持 HTTP/2 的,如果您有这方面的需求,你可以使用 Build-OpenSSL-cURL 进行构建支持 HTTP/2 功能的版本。

注意 Build-OpenSSL-cURL 中使用的是 openSSL,而目前 macOS Catalina 中则是使用 LibreSSL,如下图:

我在 Build-OpenSSL-cURL 的基础上修改了一个支持 libresll 的版本 libcurl-nghttp2-libressl-ios,可以拿去尝鲜。

备注:

  • 支持 HTTP/2 需要考虑包大小的影响
  • 目前 HTTP/2 不在一期的范围内,所以上述脚本只能保证构建出静态库,暂无做过较多的验证,请知悉。

最后

如果您看过 swift-corelibs-foundation 的相关源码, 你会发现其 NSURLSession 系列的功能(HTTP、FTP)是基于 libcurl 进行的封装。如果你想学习它,建议你直接去学习官方源码,YMHTTP 也是参考其中大量的实现,然后补充了一些尚未实现的功能以及修复了一些BUG。

这里要提一下,swift-corelibs-foundation 还是很值得一看的,在里面你会发现很多 宝藏,例如:

  • NSURLProtocol 的工作机制
  • NSOperationQueue 是如何利用 GCD 来实现的
  • NSURLSessionNSURLProtocol 的关系,它是如何实现 HTTP、HTTPS 以及 FTP 的功能(这块内容并没有实现全,有一些功能缺失,但是主功能已经完成)
  • ...

在写 YMHTTP 的过程中, 我也发现了一些 swift-corelibs-foundation 中存在的问题和缺失的功能,目前也在逐步的 PR 中。

总结

YMHTTP 的初衷是为了 "彻底" 解决 HTTP DNS 的问题,但是现在回头来看,倒像是打开了一道更大的门,给我们带来了更多的自由度。

如果您有什么建议或者是想要支持功能,请一定告诉我。

最后,感谢大家的辛苦阅读,希望能对大家有一点小小的帮助,非常感谢。

文章分类
iOS
文章标签