前言
首先来看一下OkHttp的整体结构设计。
上面这张图就是OkHttp的总体设计图。它主要是通过Dispatcher不断从RequestQueue中取出请求(Call),根据是否已经缓存调用Cache或Network这两类数据获取接口之一,从内存缓存或是服务器取得请求的数据。该引擎有同步和异步请求,同步请求通过Call.execute()直接返回当前的Response,而异步请求会把当前的请求Call.enqueue()添加(AsuncCall)到请求队列中,并通过回调的方式来获取最后结果。
同步请求
|
|
异步请求
|
|
从上述代码中可以看出,异步请求会把一个AsyncCall放入到任务队列中,而Dispatcher负责分发,让其在合适的时机执行,最终也会和同步请求一样,调用execute方法,而execute方法的逻辑也并不复杂,主要就是:
- 调用getResponseWithInterceptorChain获取服务器返回
- 通知任务分发器client.dispatcher().finished(this)该任务结束
getResponseWithInterceptorChain构建了一个拦截器链,通过依次执行该拦截器链中的每一个拦截器最终得到服务器返回。
构建拦截器链
首先来看一下getResponseWithInterceptorChain的实现。
|
|
其逻辑大致分为两部分:
- 创建一系列拦截器,并将其放入一个拦截器数组中。这部分拦截器既包括用户自定义的拦截器也包括框架内部拦截器
- 创建一个拦截器链RealInterceptorChain,并执行拦截器链的proceed方法
接下来看下RealInterceptorChain的实现逻辑。
|
|
在proceed方法中的核心代码可以看到,proceed实际上做了两件事:
- 创建下一个拦截器链。传入index + 1使得下一个拦截器链只能从下一个拦截器开始访问
- 执行索引为index的intercept方法,并将下一个拦截器链传入该方法
执行拦截器
在拦截器中会执行下一个拦截器链的proceed方法,而在下一个拦截器链中又会执行下一个拦截器链的intercept方法,所以整个执行链就在拦截器与拦截器链中交替执行,最终完成所有拦截器的操作。这也是OkHttp拦截器的链式执行逻辑。而一个拦截器的intercept方法所执行的逻辑大致分为三部分:
- 在发起请求前对request进行处理
- 调用下一个拦截器,获取request
- 对response进行处理,返回给上一个拦截器
这就是OkHttp拦截器机制的核心逻辑。所以一个网络请求实际上就是一个个拦截器执行其intercept方法的过程。而这其中除了用户自定义的拦截器外还有几个核心拦截器完成了网络访问的核心逻辑,按照先后顺序依次是:
- RetryAndFollowUpInterceptor
- BridgeInterceptor
- CacheInterceptor
- ConnectIntercetor
- CallServerInterceptor
接下来看一下不同拦截器实现的不同方法。
RetryAndFollowUpInterceptor
|
|
如上文代码所示,RetryAndFollowUpInterceptor负责两部分逻辑:
- 在网络请求失败后进行重试
- 当服务器返回当前请求需要进行重定向时直接发起新的请求,并在条件允许情况下复用当前连接
BridgeInterceptor
|
|
BridgeInterceptor主要负责以下几个部分内容:
- 设置内容长度,内容编码
- 设置gzip压缩,并在接收到内容后进行解压,省去了应用层处理数据解压的麻烦
- 添加cookie
- 设置其他报头,如User-Agent,Host,Keep-alive等。其中Keep-Alive是实现多路复用的必要步骤
CacheInterceptor
|
|
CacheInterceptor的职责很明确,就是负责Cache的管理
- 当网络请求有符合要求的Cache时直接返回Cache
- 当服务器返回内容有改变时更新当前cache
- 如果cache失效,删除
ConnectionInterceptor
|
|
ConnectionInterceptor的intercept方法只有一行关键代码:
|
|
即为当前请求找到合适的连接,可能复用已有连接也可能是重新创建的连接,返回的连接由连接池负责决定。
CallServerInterceptor
|
|
CallServerInterceptor负责向服务器发起真正的访问请求,并在接收到服务器返回后读取响应返回。
小结
以下是整个网络访问的核心步骤,总结起来如下图所示。