天天看点

OkHttp 3.7源码分析(二)——拦截器&一个实际网络请求的实现

okhttp3.7源码分析文章列表如下:

<a href="https://yq.aliyun.com/articles/78105?spm=5176.8091938.0.0.hleond">okhttp源码分析——整体架构</a>

<a href="https://yq.aliyun.com/articles/78104?spm=5176.8091938.0.0.hleond">okhttp源码分析——拦截器</a>

<a href="https://yq.aliyun.com/articles/78103?spm=5176.8091938.0.0.hleond">okhttp源码分析——任务队列</a>

<a href="https://yq.aliyun.com/articles/78102?spm=5176.8091938.0.0.hleond">okhttp源码分析——缓存策略</a>

<a href="https://yq.aliyun.com/articles/78101?spm=5176.8091938.0.0.hleond">okhttp源码分析——多路复用</a>

前一篇博客中我们介绍了okhttp的总体架构,接下来我们以一个具体的网络请求来讲述okhttp进行网络访问的具体过程。由于该部分与okhttp的拦截器概念紧密联系在一起,所以将这两部分放在一起进行讲解。

首先构造一个简单的异步网络访问demo:

<code>okhttpclient.newcall</code>实际是创建一个<code>realcall</code>实例:

<code>realcall.enqueue</code>实际就是讲一个<code>realcall</code>放入到任务队列中,等待合适的机会执行:

从代码中可以看到最终<code>realcall</code>被转化成一个<code>asynccall</code>并被放入到任务队列中,任务队列中的分发逻辑这里先不说,相关实现会放在[okhttp源码分析——任务队列]()疑问进行介绍。这里只需要知道asynccall的excute方法最终将会被执行:

<code>execute</code>方法的逻辑并不复杂,简单的说就是:

调用<code>getresponsewithinterceptorchain</code>获取服务器返回

通知任务分发器(<code>client.dispatcher</code>)该任务已结束

<code>getresponsewithinterceptorchain</code>构建了一个拦截器链,通过依次执行该拦截器链中的每一个拦截器最终得到服务器返回。

首先来看下<code>getresponsewithinterceptorchain</code>的实现:

其逻辑大致分为两部分:

创建一系列拦截器,并将其放入一个拦截器数组中。这部分拦截器即包括用户自定义的拦截器也包括框架内部拦截器

创建一个拦截器链<code>realinterceptorchain</code>,并执行拦截器链的<code>proceed</code>方法

接下来看下<code>realinterceptorchain</code>的实现逻辑:

在<code>proceed</code>方法中的核心代码可以看到,proceed实际上也做了两件事:

创建下一个拦截链。传入<code>index + 1</code>使得下一个拦截器链只能从下一个拦截器开始访问

执行索引为<code>index</code>的intercept方法,并将下一个拦截器链传入该方法

接下来再看下第一个拦截器retryandfollowupinterceptor的intercept方法:

这段代码最关键的代码是:

这行代码就是执行下一个拦截器链的proceed方法。而我们知道在下一个拦截器链中又会执行下一个拦截器的intercept方法。所以整个执行链就在拦截器与拦截器链中交替执行,最终完成所有拦截器的操作。这也是okhttp拦截器的链式执行逻辑。而一个拦截器的intercept方法所执行的逻辑大致分为三部分:

在发起请求前对request进行处理

调用下一个拦截器,获取response

对response进行处理,返回给上一个拦截器

这就是okhttp拦截器机制的核心逻辑。所以一个网络请求实际上就是一个个拦截器执行其intercept方法的过程。而这其中除了用户自定义的拦截器外还有几个核心拦截器完成了网络访问的核心逻辑,按照先后顺序依次是:

retryandfollowupinterceptor

bridgeinterceptor

cacheinterceptor

connectintercetot

callserverinterceptor

如上文代码所示,retryandfollowupinterceptor负责两部分逻辑:

在网络请求失败后进行重试

当服务器返回当前请求需要进行重定向时直接发起新的请求,并在条件允许情况下复用当前连接

bridgeinterceptor主要负责以下几部分内容:

设置内容长度,内容编码

设置gzip压缩,并在接收到内容后进行解压。省去了应用层处理数据解压的麻烦

添加cookie

设置其他报头,如<code>user-agent</code>,<code>host</code>,<code>keep-alive</code>等。其中<code>keep-alive</code>是实现多路复用的必要步骤

cacheinterceptor的职责很明确,就是负责cache的管理

当网络请求有符合要求的cache时直接返回cache

当服务器返回内容有改变时更新当前cache

如果当前cache失效,删除

connectinterceptor的intercept方法只有一行关键代码:

即为当前请求找到合适的连接,可能复用已有连接也可能是重新创建的连接,返回的连接由连接池负责决定。

callserverinterceptor负责向服务器发起真正的访问请求,并在接收到服务器返回后读取响应返回。

以上就是整个网络访问的核心步骤,总结起来如下图所示:

OkHttp 3.7源码分析(二)——拦截器&amp;一个实际网络请求的实现