在OkHttp中执行同步请求会阻塞当前线程,直到HTTP响应返回,同步请求使用的是execute()方法;而异步请求类似于非阻塞式的请求,它的执行结果一般通过接口回调的方式告知调用者,异步请求使用的是enqueue(Callback)方法;
OkHttp中不管是同步还是异步,都是通过拦截器完成网络的获取。
官网对拦截器的解释是:拦截器是OkHttp中提供的一种强大机制,它可以实现网络监听、请求以及响应重写、请求失败重试等功能。
看下面这张图:
image
在这张图中可以看到有两种拦截器,一种是APPLICATION INTERCEPTORS,也就是应用拦截器;第二种是NETWORK INTERCEPTORS,表示网络拦截器。除了这两种拦截器,重要的是中间OkHttp core这块,这是OkHttp提供的内部拦截器。
看下图:
image
这是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<Interceptor> 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方法在上面介绍过了,作用是创建下一个拦截器链,这样就说明了整个拦截器链的执行过程就像链条一样,一环扣一
作者:顾林海
链接:https://www.jianshu.com/p/084b4d4ede11
共同学习,写下你的评论
评论加载中...
作者其他优质文章