OKHttp源码解析(二)——拦截器

学习参考资料:OKHttp源码解析  OKHttp源码分析——拦截器  OKhttp完全解析-拦截器

上一篇大概记录了一下OKHttp的整体结构设计,这里引用泡网的一张总体设计图

OKHttp总体设计

上面这张就是OKHttp总体设计图了,它主要是通过Dispatcher不断从RequestQueue中取出请求(Call),根据是否已缓存调用Cache或 Network这两类数据获取接口之一,从内存缓存或是服务器取得请求的数据。该引擎有同步和异步请求,同步请求通过Call.execute()直接返 回当前的Response,而异步请求会把当前的请求Call.enqueue添加(AsyncCall)到请求队列中,并通过回调(Callback) 的方式来获取最后结果。

enqueue队列

这里可以看到mOkHttpClient.newCall(rq).enqueue(newMyCallBack(parser) {});中的Call.enqueue其实就是最终会执行将一个Call转换为一个AsyncCall添加到队列中,这里的分发队列,会在后续笔记中详细介绍。

上一篇笔记中提到,AsyncCall继承了NamedRunnable实现了它的抽象方法execute()

execute

execute方法里面是调用了getResponseWithIntercepteorChain()方法获取服务器的返回,然后调用getDispatcher().finish();通知任务分发器该任务已结束。

getResponseWithIntercepteorChain():顾名思义,通过这个拦截器链中的每一个拦截器之后得到服务器的返回结果。

看源码中这个方法得知我们的猜想没有错,他就是一个构建了一个拦截器链,通过依次执行该拦截器链中的每一个拦截器最终得到服务器返回。

官方文档的解释:观察,修改以及可能短路的请求输出和响应请求的回来。通常情况下拦截器用来添加,移除或者转换请求或者回应的头部信息。

Intercepteor

这个方法的实现其实就是将很多个拦截器包括框架内部的,用户自定义的,统统放到一个拦截器数组里,创造这个RealInterceptorChain这个拦截器链,最后实现这个proceed()这个方法

proceed

通过源码我们可以看到,这个proceed()方法中采用列表的形式追踪拦截器,拦截器会被有序调用

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

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

    通过官方文档的描述以及源码的分析,我们心中对拦截器大概有个理解印象了,下面,就记录一下,不同的拦截器实现的不同方法:

1.RetryAndFollowUpInterceptor:负责失败重试以及重定向

RetryAndFollowUpInterceptor

以此为例,可以看到一行很关键的代码,response= ((RealInterceptorChain) chain).proceed(request, streamAllocation,null,null);

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

一个拦截器的intercept方法所执行的逻辑大致分为三部分:

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

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

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

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

RetryAndFollowUpInterceptor

BridgeInterceptor

CacheInterceptor

ConnectIntercetot

CallServerInterceptor

RetryAndFollowUpInterceptor:如上文代码所示,RetryAndFollowUpInterceptor负责两部分逻辑:在网络请求失败后进行重试,当服务器返回当前请求需要进行重定向时直接发起新的请求,并在条件允许情况下复用当前连接

2.BridgeInterceptor :负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应

BridgeInterceptor主要负责以下几部分内容:1.设置内容长度,内容编码 2.设置gzip压缩,并在接收到内容后进行解压。省去了应用层处理数据解压的麻烦,3.添加cookie 4.设置其他报头,如User-Agent,Host,Keep-alive等。其中Keep-Alive是实现多路复用的必要步骤

3.CacheInterceptor :负责读取缓存直接返回、更新缓存

CacheInterceptor的职责很明确,就是负责Cache的管理:1.当网络请求有符合要求的Cache时直接返回Cache;2.当服务器返回内容有改变时更新当前cache;3.如果当前cache失效,删除

4.ConnectIntercetot:负责和服务器建立连接

ConnectInterceptor

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

RealConnection connection= streamAllocation.connection();

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

5.CallServerInterceptor:负责向服务器发送请求数据、从服务器读取响应数据

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

图片及解释来源:https://yq.aliyun.com/articles/78104?t=t1

最后补充一句,拦截器分为网络拦截器和应用拦截器,注册网络拦截器和注册应用拦截器很类似。只是通过networkInterceptors()方法取代了interceptore()方法。

注册网络拦截器:client.networkInterceptors().add(new xxxInterceptor);

注册应用拦截器:client.interceptore().add(new xxxInterceptor);

推荐阅读更多精彩内容