RetryAndFollowUpInterceptor
RetryAndFollowUpInterceptor是用于失败重试及重定向的拦截器。在okHttp中,无论是调用同步execute方法或者是异步enqueue方法最终都会调用响应拦截链方法——getResponseWithInterceptorChain()。该方法主要是建立各种拦截器,RetryAndFollowUpInterceptor就是其中一种
getResponseWithInterceptorChain方法的源码如下图所示:
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
//失败重试和重定向拦截器
interceptors.add(new RetryAndFollowUpInterceptor(client));
//桥接拦截器:用于处理请求和返回的拦截器
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//缓存拦截器:负责把网络请求的响应写入缓存和从缓存中读取响应
interceptors.add(new CacheInterceptor(client.internalCache()));
//与服务端建立连接,并获取通向服务端的输入流和输出流
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
//向服务端发送客户端的请求数据并封装服务端返回的response
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
如上代码所示,拦截器最终都会加入到一个 List链表中,然后通过RealInterceptorChain封装拦截器的相关信息,注意0这个数字,这个参数对应着RealInterceptorChain构造函数的index,是List链表的角标,主要用于判断是否超出List的大小或者取出List中的对应的拦截器等。RealInterceptorChain的引用是接口Chain,chain.proceed(originalRequest)是调用的RealInterceptorChain的proceed方法,proceed方法如下所示:
@Override public Response proceed(Request request) throws IOException {
return proceed(request, transmitter, exchange);
}
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.exchange != null && !this.exchange.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.exchange != 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 next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (exchange != 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;
}
值得分析的是如下几行代码
if (index >= interceptors.size()) throw new AssertionError();//1
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);//2
Interceptor interceptor = interceptors.get(index);//3
Response response = interceptor.intercept(next);//4
- 第1行代码,如果索引index大于等于拦截器数量,则抛出异常。
- 第2行代码,封装下一个拦截链对象,这里指的是BridgeInterceptor拦截器
- 第3行代码,获取拦截器对象,这里是第一个拦截器RetryAndFollowUpInterceptor
- 然后执行RetryAndFollowUpInterceptor拦截器的intercept方法,并将封装BridgeInterceptor拦截器的对象传递给intercept方法
所以接下来分析RetryAndFollowUpInterceptor拦截器的intercept方法
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Transmitter transmitter = realChain.transmitter();
int followUpCount = 0;
Response priorResponse = null;
while (true) {
transmitter.prepareToConnect(request);
if (transmitter.isCanceled()) {
throw new IOException("Canceled");
}
Response response;
boolean success = false;
try {
response = realChain.proceed(request, transmitter, null);
success = true;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), transmitter, false, request)) {
throw e.getFirstConnectException();
}
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, transmitter, requestSendStarted, request)) throw e;
continue;
} finally {
// The network call threw an exception. Release any resources.
if (!success) {
transmitter.exchangeDoneDueToException();
}
}
// Attach the prior response if it exists. Such responses never have a body.
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
Exchange exchange = Internal.instance.exchange(response);
Route route = exchange != null ? exchange.connection().route() : null;
Request followUp = followUpRequest(response, route);
if (followUp == null) {
if (exchange != null && exchange.isDuplex()) {
transmitter.timeoutEarlyExit();
}
return response;
}
RequestBody followUpBody = followUp.body();
if (followUpBody != null && followUpBody.isOneShot()) {
return response;
}
closeQuietly(response.body());
if (transmitter.hasExchange()) {
exchange.detachWithViolence();
}
if (++followUpCount > MAX_FOLLOW_UPS) {
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
request = followUp;
priorResponse = response;
}
}
暂时不分析里面的内容,里面有行如下代码:
response = realChain.proceed(request, transmitter, null);
注意到这里realChain是之前将BridgeInterceptor拦截器封装到RealInterceptorChain对象的引用,所以这其实是一个递归,格式如下:
public Response proceed(){
Response response = intercept();
return response;
}
public Response intercept(){
Response response = proceed();
return response;
}