阅读 590

从http协议的角度来理解Okhttp

Okhttp 执行流程简单回顾

基本流程:

eventListener : 这个东西主要是一个监听器,监听整个okhttp的连接建立以及释放等(tcp和http都可以监听到) 看下 newRealCall的这个参数

OkHttpClient client :这个主要是针对一些http属性的设置,这个放到后面再讲。

Request originalRequest: 这个 就是我们传递进去的request,但是为啥参数叫originalRequest?其实也不难 主要是因为 我们传进去的request 未必就是我们最终请求出去的request 因为会经过责任链的修改,这个也放到后面讲

这里我们来看下dispatcher

maxRequests:可以同时运行的最大请求数,也就是说 一个okhttp的client 可以同时发64个请求去

maxRequestsPerHost:对 每个域名 我们最多同时只能有5个请求。

这个参数的实际意义是 针对每个域名,okhttp最多可以发起5条tcp连接。

readyAsyncCalls: 这个是将要被发出去但是目前还没发出去的请求

runningAsyncCalls:正在运行中的请求

整体来说 dispatcher就是一个 线程调度器

看下执行过程;

可以看出来 真正执行就是AsyncCall这个runnable

这里可以看出来 真正执行的是 AsyncCall的 execute方法

分析到这里 我们可以得出来2个结论:

整个请求的发出 包括 结果的返回其实都是在这个 getResponseWithInterceptorChain 方法中

另外就是可以看出来 okhttp的结果回调 其实是在子线程中

OkhttpClient 重难点参数解析

这里 我会挑一些 重难点的参数进行解析,因为别的文章 大多数讲这些细节讲的很少。一些大家都讲的 我就不再去讲了。

我们主要看这3个参数

HostnameVerifier: 这个看起来叫 域名验证器,其实本质上是个 证书校验的东西,

就是做证书校验 的,可以看下他的校验过程

这里注意看 为啥这里是取一个数组的 头部位置?取第一个元素? 这里实际涉及到https的知识了,实际山 在tls连接建立的过程中, 服务端给客户端传递的证书 不仅包含 服务端自己的证书,还包含他签名机构的证书

打开一个浏览器看一下,我们就看百度的证书,你看 是一个链式结构吧,最下面是百度的证书, 谁给他签发的?二级签名机构签发的

我们加个日志 看下对不对 是不是这样:

然后继续看他的验证过程:

其实就是验证一下 证书中的

这里其实就是 验证网站证书中的 域名信息 是不是 和目的访问地址是匹配的。比如我访问的baidu的域名,你给我一个证书 是个谷歌的域名 那肯定校验失败 。

做过https证书申请的人都知道 申请证书的时候 是要提交域名的,你要证明 这个域名的持有者是你自己

certificateChainCleaner: 证书清理的作用,前面提到建立tls连接的时候 ,服务端返回给客户端的证书是一环套着 一环,因为服务器的证书会被机构签名,这里就是将外面包裹的签名结构的证书都剥离开,只留下最终的服务端自己的证书

CertificatePinner: 证书固定器

这个就是用来固定证书的,比方说我的项目 我不想申请ca等机构的签名,我不需要去他那边注册,我就搞一个私有的https证书就可以了。 那我们就可以把这个 公钥的值 内置在 在certificatePinner中。 这样也可以通过tls 验证。

或者说 我就是想内置证书,用来防抓包等等 也可以用这个来内置。

但是这个有一个缺点就是 你一旦内置在app中,万一哪天你的服务端说我要更新证书 那就麻烦了。 因为公钥 对不上。线上的用户访问就全部失败了。

dns: 查找dns的

这里唯一要注意的就是 通常而言 一个域名是配置了多个ip地址的,okhttp 在这里做的比较好的是当一个ip tcp连接不成功的时候, 会自动切换到另外一个ip 尝试继续

重定向: 重定向相关

是否允许重定向,其实这里主要就是要关注这个 followSsl的这个重定向配置,有的时候会发生你目标地址是https 然后重定向到一个http地址的情况,这种其实挺危险的,这里可以配置这个属性

getResponseWithInterceptorChain 详解

先搞清楚一个责任链的概念就可以了

其实okhttp责任链的概念很简单;

一条链子上有n个节点。 执行顺序如下:

第一个节点 执行自己的 前置操作------第二个节点执行自己的前置操作-----第三个----第n个节点执行自己的前置操作

此时 第n个节点 发现自己后面没有节点了,那第n个节点执行完前置操作以后 就继续执行自己的后置操作,都执行完毕以后

就可以把执行结果 返回到 第n-1个节点上, 然后第n-1个节点 拿到第n个节点的结果 就执行自己的后置操作

如此,一直到 第二个节点把自己的后置操作的结果 返回给第一个节点,然后第一个节点的全部操作就结束了。

搞清楚这个逻辑 ,再看这些代码就会简单不少。 同时在看代码的时候 谨记一点

只要是proceed 方法被调用的地方 就意味着 在这个地方 调用链的流程进入到了下一个chain中, 在proceed 之前都是前置操作,proceed 之后 都是后置操作了。

RetryAndFollowUpInterceptor: 顾名思义 这里其实主要是为了请求连接失败 重试用的。

这里很简单 可以看出来是一个for循环, 连接如果失败了 会往上抛出异常,然后在异常中 continue 进行连接重试

BridgeInterceptor: 这个主要是拼接一些通用的http header 请求之前会添加很多header ,这里注意 他会自动的帮我们添加gzip这个属性

继续看:

这里也是一样的,当请求返回了之后,在这里 也会进行gzip的压缩处理

CacheInterceptor 缓存相关的

这里唯一要注意的就是 如果触发了缓存相关的机制,在这里就提前结束了责任链了 后续的所有链都不会再走了。

ConnectInterceptor 这里是就是okhttp中比较核心的地方了

他是整个tcp-http 的编解码核心。实际上 tcp和tls连接也是在这个过程里面建立的

在这里 拿到 httpcodec 以后 就可以进入到下一个流程

CallServerInterceptor

这里 就是往 socket中写输出和读数据的地方了。也是整个链的结束的地方

纵观整个okhttp的责任链 其实是不难的。无非是一些细节问题要考虑清楚 要慢慢花心思 慢慢读。

另外就是

很多人都知道 interceptors和networkInterceptors 区别 但是讲清楚原因的很少 看完前面的分析其实 大概也就知道了 最主要的原因就是 bridge这个拦截器 会对request进行 gzip压缩 对response进行解压缩, network 在他后面 那么 network拿到的就是原始的byte数据了,所以其实大部分场景下 network这个拦截器 对普通开发者来说是没啥用的。 你可以理解为这是一个面向特殊场景 要直接处理 bytes数据的一个勾子

文章分类
Android
文章标签