OkHttp怎样完成一次网络请求的

​ OkHttp作为目前使用最广泛的网络请求库,一直以高性能和灵活性强著称,为了让项目里使用的ExoPlayer播放器支持Http/2协议,最近做了给ExoPlayer集成OkHttp插件的工作,但是集成以后有一个问题是连续点击播放器的快进或者快退按钮,播放器就卡在了那里。为了找到解决问题的方法,花了些时间把OKHttp源码过了一遍。很多开发者已经对OkHttp做了详细的源码解析,这篇文章基于OkHttp 4.0.x版本,着重介绍OkHttp进行一次网络请求的基本过程。

​ 怎么用OkHttp发起网络请求,官网上有介绍和代码示范,网络请求可以分为两种类型,同步请求和异步请求,同步请求在当前线程执行网络请求任务,异步请求在当前线程使用ExecutorService, 即线程池执行网络请求操作,这里以同步请求为例:

1
OkHttpClient client = new OkHttpClient();
2
3
String run(String url) throws IOException {
4
  Request request = new Request.Builder()
5
      .url(url)
6
      .build();
7
8
  try (Response response = client.newCall(request).execute()) {
9
    return response.body().string();
10
  }
11
}

OkHttpClient.newCall(request).execute()被调用后,RealCall的两个方法.execute() 和getResponseWithInterceptorChain() 被依次执行,接着就把请求的任务交给了RealInterceptorChain, 源码里对RealInterceptorChain添加的注释是:

A concrete interceptor chain that carries the entire interceptor chain: all application interceptors, the OkHttp core, all network interceptors, and finally the network caller.

一个带有整个拦截器链的具体拦截器链,包含了所有应用程序的拦截器,是okHttp的核心,所有的网络拦截器,最后的网络请求执行者。

​ RealInterceptorChain会依次调用用户添加的拦截器和OkHttp自带的拦截器,处理整个网络请求的流程。拦截器是OkHttp项目的精华,源码里对拦截器的解释是

1
Observes, modifies, and potentially short-circuits requests going out and the corresponding
2
responses coming back in. Typically interceptors add, remove, or transform headers on the request or response.

观察,修改请求和对应的响应,通常,拦截器用来添加,删除,或者转换请求头或者响应头信息。

​ 拦截器也可以集中处理请求的响应,比如有些server的API要求用户处于登陆状态才能访问,返回的结果是这个样子的:

1
{
2
	"status":"1",
3
	"message":"..."
4
	"result":"..."
5
}

status代表客户端和服务端约定的状态码,message表示返回的提示信息,result是客户端需要的真正数据,如果用户处于未登录状态就跳转到登陆页,如果是已登陆状态,去除status, message等这些无用信息,直接返回给客户端result结果,这里不再描述实现细节。

拦截器在OKHttp中被定义成了接口,它的的核心方法是:

1
fun intercept(chain: Chain): Response

接收的入参是RealInterceptorChain,返回网络请求的响应结果,

RealInterceptorChain的proceed()方法依次递归调用每个拦截器,实现对网络请求和响应的处理,实现方式和android中的时间传递机制异曲同工之妙,设计模式中责任链模式的很好实践,拦截器的调用顺序如下图:

img

User Interceptors是通过OkHttpClient().newBuilder().addInterceptor() 给添加的自定义拦截器,

OKHttp自带的有5个拦截器:

​ RetryAndFollowUpInterceptor

​ This interceptor recovers from failures and follows redirects as necessary

​ 重试和追踪拦截器,负责重试那些可以恢复的网络请求

​ BridgeInterceptor

​ Bridges from application code to network code. First it builds a network request from a user
request. Then it proceeds to call the network. Finally it builds a user response from the network
response.

​ 从应用程序代码到网络代码的桥梁。 对请求和响应的数据做集中处理

CacheInterceptor- 处理数据缓存的拦截器

ConnectInterceptor- 建立网络连接的拦截器

​ 对于不使用http/2协议的请求,OkHttp使用了ConnectionPool复用之前建立的连接,ConnectionPool

Manages reuse of HTTP and HTTP/2 connections for reduced network latency. HTTP requests that share the same [Address] may share a [Connection]. This class implements the policy of which connections to keep open for future use.
Currently, this pool holds up to 5 idle connections which will be evicted after 5 minutes of inactivity.

​ 连接池管理HTTP和HTTP / 2连接的重用,以减少网络延迟。 共享相同地址(host)的HTTP请求可以共享连接,目前,该池最多可容纳5个空闲连接,这些连接将在5分钟不活动后被驱逐。

​ CallServerInterceptor- 拦截器链的最后一个拦截器,网络请求的最终执行者。

​ 同步请求过程中,代码Response response = client.newCall(request).execute() 返回,表示这次请求结束,但并不表示数据已经从server完全接收,因为从server接收数据的操作是在一个新的线程里执行,猜测OkHttp这么做是为了减少同步请求的等待时长。

以上就是OkHttp执行一个网络请求的基本流程,更多细节还是要到源码里去探索。