OkHttp源码解析

11 篇文章 0 订阅
2 篇文章 0 订阅

OkHttp 是什么

  • 官方解释:适用于 Android 和 Java 应用程序的 HTTP 和 HTTP / 2 的客户端
  • OKHTTP 是一个高效的 HTTP 库
  • 网络请求发展:HttpURLConnection —> Apache HTTP Client —> Volley —-> okHttp
  • SPDY -> HTTP 2

HTTP 是现代应用网络的方式。这就是我们交换数据和媒体的方式。有效地执行 HTTP 可以加快您的负载并节省带宽。

OkHttp 是一个默认有效的 HTTP 客户端:

1. HTTP / 2 支持允许对同一主机的所有请求共享套接字。
2. 连接池减少了请求延迟(如果 HTTP / 2 不可用)。
3. 透明 GZIP 缩小了下载大小。
4. 响应缓存可以完全避免网络重复请求。
5. 当网络很麻烦时,OkHttp 坚持不懈:它将从常见的连接问题中无声地恢复。
6. 如果您的服务有多个 IP 地址,如果第一次连接失败,OkHttp 将尝试备用地址。这对于 IPv4 + IPv6 和
   冗余数据中心中托管的服务是必需的。
7. OkHttp 支持现代 TLS 功能( TLS1.3,ALPN,证书固定 )。它可以配置为回退以实现广泛的连接。

使用 OkHttp 很容易。它的 请求 / 响应 API 采用流畅的构建器和不变性设计。它支持同步阻塞调用和带回调的异步调用。

OkHttp 支持 Android 5.0+(API 级别 21+)和 Java 8+。

OkHttpClient

该类继承了接口 Cloneable, Call.Factory, WebSocket.Factory

Call

  • execute() 是同步方法
  • enqueue(responseCallback: Callback) 是异步方法
  • 同步请求生成的是 RealCall 对象,而异步请求生成的是 AsyncCall 对象。AsyncCall 说到底其实就是 Runnable 的子类
  • 如果可以执行,则对当前请求添加监听器等操作,然后将请求 Call 对象放入调度器 Dispatcher 中。最后由拦截器链中的各个拦截器来对该请求进行处理,返回最终的 Response

Dispatcher调度器

  • Dispatcher 是保存同步和异步 Call 的地方,并负责执行异步 AsyncCall

  • 针对同步请求,Dispatcher 使用了一个 Deque 保存了同步任务;针对异步请求,Dispatcher 使用了两个 Deque,一个保存准备执行的请求,一个保存正在执行的请求,为什么要用两个呢?因为 Dispatcher 默认支持最大的并发请求是 64 个,单个 Host 最多执行 5 个并发请求,如果超过,则 Call 会先被放入到 readyAsyncCall 中,当出现空闲的线程时,再将 readyAsyncCall 中的线程移入到 runningAsynCalls 中,执行请求,以下是流程图

    image

WebSocket

Transmitter

应用层和网络层间的桥梁

Interceptor

  • BridgeInterceptor:为请求(request before)添加请求头,为响应(Response Before)添加响应头
    采用 Gzip 压缩后可以大幅减少传输内容大小,这样可以提高传输速度,减少流量的使用。OkHttp 是默认支持 Gzip 解压缩的,不需要额外配置的,若用户自己添加了压缩则需要自己添加解压缩。客户端发起请求时在请求头里增加 Accept-Encoding:gzip,服务端响应时在返回的头信息里增加 Content-Encoding:gzip,这表示传输的数据是采用 Gzip 压缩的。
  • CallServerInterceptor: 该拦截器就是利用 HttpCodec 完成最终请求的发送。
  • ConnectionInterceptor:获得一个安全有效的连接。
  • CacheInterceptor:处理 ETag、Last-Modified 等缓存相关的请求头,若缓存可用,则使用 Gzip 进行处理,CacheStrategy 是一个缓存策略类,该类告诉 CacheInterceptor 是使用缓存还是使用网络请求 (DiskLruCache)

根据缓存策略类返回的结果:

1.  如果网络不可用并且无可用的有效缓存,则返回504错误;
2.  继续,如果不需要网络请求,则直接使用缓存;
3.  继续,如果需要网络可用,则进行网络请求;
4.  继续,如果有缓存,并且网络请求返回 HTTP_NOT_MODIFIED,说明缓存还是有效的,则合并网络响应和缓存结果。同时更新缓存;
5.  继续,如果没有缓存,则写入新的缓存;  

缓存策略的判断流程:

1.  没有缓存,直接网络请求;
2.  如果是 https,但没有握手,直接网络请求;
3.  不可缓存,直接网络请求;
4.  请求头 nocache 或者请求头包含 If-Modified-Since 或者 If-None-Match,则需要服务器验证本地缓存是不是
    还能继续使用,直接网络请求;
5.  可缓存,并且 ageMillis + minFreshMillis < freshMillis + maxStaleMillis(意味着虽过期,但可用,
    只是会在响应头添加 warning),则使用缓存;
6.  缓存已经过期,添加请求头:If-Modified-Since 或者 If-None-Match,进行网络请求;

ConnectionSpec

具体的安全性 vs 连通性的决定是由ConnectionSpec实现的 JavaDoc

OkHttp 尝试平衡两个相互竞争的要素:

连通性 (Connectivity):连接到尽可能多的服务器。这包括运行最新版本 boringssl 的服务器和不太过时的老版本 OpenSSL 的服务器。
连接的安全性 (Security):这包括远程web服务器证书验证,和对私密数据交换的强加密。

在与 HTTPS 服务器协商一个连接时,OkHttp 需要知道提供哪种 TLS 版本 (TLSversions) 和密码套件 (cipher suites)。一个希望最大化连通性的客户端会包含废弃的 TLS 版本和弱设计的密码套件。一个希望最大化安全性的严格的客户端将会限制只使用最新的 TLS 版本和最强的密码套件。

OkHttp 包含三种内置的连接策略:

MODERN_TLS:     连接到最新的 HTTPS 服务器的安全配置。
COMPATIBEL_TLS: 连接到过时的 HTTPS 服务器的安全配置。
CLEARTEXT:      用于 http:// 开头的 URL 的非安全配置。

默认情况下,OkHttp 将会尝试 MODERN_TLS 连接,如果当前配置失败,会退回到 COMPATIBLE_TLS 连接。

每种连接策略中,具体的 TLS 版本和密码套件在每个版本中都可能会变。例如,在 OkHttp2.2 中,我们禁用了 SSL 3.0,以应对 POODLE攻击;在 OkHttp2.3 中我们禁用了 RC4。同你的桌面 web 浏览器一样,使用最新的 OkHttp 版本是保证安全的最好方法。

你可以建立自己的连接策略,使用自定义的 TLS 版本和密码套件。

关于自签名证书

Retrofit 使用自签名证书进行 HTTPS 请求的教程

整体结构

image

Kotlin知识点

由于新版本的 OkHttp 使用的是 Kotlin,所以此处同时记录关于 Kotlin 的知识点

  • companion object 类的内部类(伴生对象)的声明关键字,外部调用可以忽略内部类名,直接使用类名调用内部类的成员。声明时也可以省略内部类名,调用时使用 companion
class MyClass {
    companion object { }
}
val x = MyClass.Companion

参考文章

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值