前面说到的同步请求RealCall和异步请求AsyncCall,在执行execute方法时都会执行下面一句:
Response response = getResponseWithInterceptorChain();
这一句就是调用了拦截器链,执行了一系列操作,完成了请求访问,并将结果返回。
RealCall#getResponseWithInterceptorChain
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.创建一个拦截器堆/链
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());//用户自定义的拦截器,先加入链,先执行
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());//添加 OkHttpClient 时设置的 networkInterceptors;
}
interceptors.add(new CallServerInterceptor(forWebSocket));//最后 添加 负责向服务器发送请求数据、从服务器读取响应数据的拦截器
//使用上面创建的的拦截器,创建一个拦截器链
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//执行拦截器链的proceed方法,依次执行上面所有的拦截器的功能
return chain.proceed(originalRequest);
}
上述代码说明:
-
创建了一个Interceptor列表;
-
依次添加拦截器,添加的顺序为:client.interceptors()–>retryAndFollowUpInterceptor–>BridgeInterceptor–>CacheInterceptor–>ConnectInterceptor–>networkInterceptors–>CallServerInterceptor;
-
创建Interceptor.Chain对象,参数有:
-
拦截器集合interceptors;
-
originalRequest;
-
RealCall;
-
eventListener;
-
连接超时时间,读超时时间,写超时时间。
-
RealInterceptorChain的创建
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
public interface Interceptor {
//负责拦截
Response intercept(Chain chain) throws IOException;
interface Chain {
//可以返回Request对象
Request request();
//前进,推动继续进行,负责不断执行下一个拦截器
Response proceed(Request request) throws IOException;
/**
* Returns the connection the request will be executed on. This is only available in the chains
* of network interceptors; for application interceptors this is always null.
*/
//返回当前请求所在的连接对象。
@Nullable Connection connection();
//返回Call对象
Call call();
}
}
public final class RealInterceptorChain implements Interceptor.Chain {
private final List<Interceptor> interceptors;//拦截器集合,即拦截器链中的拦截器
private final StreamAllocation streamAllocation;//流分配器
private final HttpCodec httpCodec;//Http 流
private final RealConnection connection;//真正的连接对象
private final int index;//final类型的,是访问拦截器集合的index
private final Request request;//请求Request
private final Call call;//传过来的RealCall
private final EventListener eventListener;
private final int connectTimeout;//连接超时时间
private final int readTimeout;//读超时时间
private final int writeTimeout;//写超时时间
private int calls;//表示访问拦截器链的次数
public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
this.interceptors = interceptors;
this.connection = connection;//null
this.streamAllocation = streamAllocation;//null
this.httpCodec = httpCodec;//null
this.index = index;//0
this.request = request;
this.call = call;
this.eventListener = eventListener;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
}
}
通过以上代码,创建完成了RealInterceptorChain对象。接下来就是调用proceed方法。
RealInterceptorChain#proceed
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
//目前入参情况:
//request != null
//streamAllocation == null
//httpCodec == null
//connection == null
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//判断当前的访问索引是否超过了拦截器集合中拦截器的数量,index是不断增加的。
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
//如果当前已经有一个流,确认当前这个Request是否可以用它这个链接
if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
//创建下一个RealInterceptorChain对象。这里的传入的拦截器集合访问的索引是index+1,call也是增加了1.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);//获取当前index对应的Interceptor;
Response response = interceptor.intercept(next);//拦截,处理当前拦截器的负责的事务,并继续调用后续的拦截器,并返回请求结果。
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;//返回响应
}
上面,第一次创建RealInterceptorChain对象,并调用proceed方法 的过程:
-
判断当前的访问索引是否超过了拦截器集合中拦截器的数量;
-
创建下一个RealInterceptorChain对象。这里的传入的拦截器集合访问的索引是index+1;
-
获取当前index对应的interceptor;
-
调用当前interceptor的intercept方法,处理当前拦截器负责的业务,并唤起下一个拦截器;
-
当前request != null
streamAllocation == null httpCodec == null connection == null
拦截器集合中的第一个拦截器为retryAndFollowUpInterceptor,首先将进入到它的intercept方法:
RetryAndFollowUpInterceptor#intercept
public final class RetryAndFollowUpInterceptor implements Interceptor {
/**
* How many redirects and auth challenges should we attempt? Chrome follows 21 redirects; Firefox,
* curl, and wget follow 20; Safari follows 16; and HTTP/1.0 recommends 5.
*/
private static final int MAX_FOLLOW_UPS = 20;
private final OkHttpClient client;//前面创建的OkHttpClient对象
private final boolean forWebSocket;
private StreamAllocation streamAllocation;
private Object callStackTrace;
private volatile boolean canceled;//请求是否被取消
//Chain为 RealInterceptorChain对象,在上一个拦截器中创建并传入到这里
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();//获取Request对象
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Call call = realChain.call();//获取RealCall对象
EventListener eventListener = realChain.eventListener();
//创建StreamAllocation对象,之前都是null。
streamAllocation = new StreamAllocation(client.connectionPool(), createAddress(request.url()),
call, eventListener, callStackTrace);
int followUpCount = 0;//从定向次数
Response priorResponse = null;
while (true) {//一直循环
if (canceled) {//判断是否取消了请求
streamAllocation.release();//释放资源
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
//继续执行下一个拦截器,看上面的proceed方法
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), false, request)) {
throw e.getLastConnectException();
}
releaseConnection = false;
continue;
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, requestSendStarted, request)) throw e;
releaseConnection = false;
continue;
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
}
}
和上述过程类似,将继续执行下一个拦截器的intercept方法.
上面就了解了拦截器链是怎么依次执行每一个拦截器的。
总结一下拦截器链中拦截器的调用过程中: