本平台的文章更新会有延迟,大家可以关注微信公众号-顾林海,包括年底前会更新kotlin由浅入深系列教程,目前计划在微信公众号进行首发,如果大家想获取最新教程,请关注微信公众号,谢谢
在OkHttp中执行同步请求会阻塞当前线程,直到HTTP响应返回,同步请求使用的是execute()方法;而异步请求类似于非阻塞式的请求,它的执行结果一般通过接口回调的方式告知调用者,异步请求使用的是enqueue(Callback)方法;
OkHttp中不管是同步还是异步,都是通过拦截器完成网络的获取。
官网对拦截器的解释是:拦截器是OkHttp中提供的一种强大机制,它可以实现网络监听、请求以及响应重写、请求失败重试等功能。
看下面这张图:
在这张图中可以看到有两种拦截器,一种是APPLICATION INTERCEPTORS,也就是应用拦截器;第二种是NETWORK INTERCEPTORS,表示网络拦截器。除了这两种拦截器,重要的是中间OkHttp core这块,这是OkHttp提供的内部拦截器。
看下图:
这是OkHttp提供给我们的拦截器,内部是以拦截器的链的形式执行HTTP的请求,其中RetryAndFollowUpInterceptor是重试和失败重定向拦截器,BridgeInterceptor是桥接和适配拦截器,CacheInterceptor是缓存拦截器,ConnectInterceptor是连接拦截器,负责建立可用的连接,CallServerInterceptor负责将HTTP的请求写入网络的IO流中,并且从网络IO流中读取服务端返回给客户端的数据。
看过前面几节的同学应该知道,无论是同步请求还是异步请求,最终执行网络请求并获取的Response都是通过getResponseWithInterceptorChain()方法获取的,代码如下。
//异步请求
@Override protected void execute() {
boolean signalledCallback = false;
try {
//重点1 使用拦截器链
Response response = getResponseWithInterceptorChain();
...
} catch (IOException e) {
...
} finally {
回收请求
client.dispatcher().finished(this);
}
}
//同步请求
@Override public Response execute() throws IOException {
//第一步:判断同一Http是否请求过
...
//捕捉Http请求的异常堆栈信息
...
//监听请求开始
...
try {
//第二步:同步请求添加到同步队列中
...
//第三步:使用拦截器链
Response result = getResponseWithInterceptorChain();
...
} catch (IOException e) {
...
} finally {
//第四步:回收请求
client.dispatcher().finished(this);
}
}
getResponseWithInterceptorChain()方法返回的就是我们网络请求的响应结果Response对象。
进入getResponseWithInterceptorChain()方法:
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List interceptors = new ArrayList<>();
//用户自定义的拦截器
interceptors.addAll(client.interceptors());
//添加OkHttp提供的五个拦截器以及networkInterceptors
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
//标记1
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//标记2
return chain.proceed(originalRequest);
}
getResponseWithInterceptorChain方法一开始将我们需要的拦截器添加到一个集合中,其中就包括我们自定义的拦截器以及上面提到的几种拦截器。
接着在标记1处创建了一个RealInterceptorChain对象,传入的第一个参数就是上面的添加的一系列拦截器,创建完毕后,在标记2处执行RealInterceptorChain对象的proceed方法。
进入RealInterceptorChain的proceed方法:
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
继续往下看:
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
...
//标记1
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
//标记2:取出index位置的拦截器
Interceptor interceptor = interceptors.get(index);
//标记3
Response response = interceptor.intercept(next);
...
return response;
}
在标记1处又创建了一个RealInterceptorChain对象,在创建对象时,传入的第五个参数是index+1,这样的话在下次访问时,只能从下一个拦截器开始进行访问,而不能从当前拦截器。
在标记2处取出第index位置的拦截器。
在标记3处将代表下一个拦截器的链的RealInterceptorChain对象传入当前位置的拦截器中,在当前拦截器链中执行请求,获取Response后依次返回给它的上一个拦截器,如果当前拦截器没有获取Response就继续调用RealInterceptorChain对象的prceed方法来创建下一个拦截器链,就这样拦截器链一层一层的调用,这样所有的拦截器链构成了一个完整的链条。
到目前为止,总结如下:
创建一系列拦截器,并将其放入一个拦截器list集合中。
创建一个拦截器链RealInterceptorChain,并执行拦截器链的proceed方法,这个proceed方法的核心是继续创建下一个拦截器链。
我们看下RetryAndFollowUpInterceptor这个拦截器,它是重试和失败重定向拦截器。
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
...
RealInterceptorChain realChain = (RealInterceptorChain) chain;
...
response = realChain.proceed(request, streamAllocation, null, null);
...
}
可以看到RetryAndFollowUpInterceptor拦截器的intercept方法,内部又执行了传递进来的RealInterceptorChain对象的proceed方法,而proceed方法在上面介绍过了,作用是创建下一个拦截器链,这样就说明了整个拦截器链的执行过程就像链条一样,一环扣一环。
搜索微信“顾林海”公众号,定期推送优质文章。