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中的时间传递机制异曲同工之妙,设计模式中责任链模式的很好实践,拦截器的调用顺序如下图:
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执行一个网络请求的基本流程,更多细节还是要到源码里去探索。