RetryAndFollowUpInterceptor
RetryAndFollowUpInterceptor
有兩個功能,一個是重試,一個是重定向。如果
Call
被取消,
RetryAndFollowUpInterceptor
将抛出異常。
我們來一起分析一下。
public final class RetryAndFollowUpInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Call call = realChain.call();
EventListener eventListener = realChain.eventListener();
StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(request.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
......
}
}
上面代碼主要是建立
StreamAllocation
對象。後面還會再做分析,它用于協調
Connection
,
Stream
,
Call
。
public final class RetryAndFollowUpInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
......
int followUpCount = 0;
Response priorResponse = null;
while (true) {
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
·····
}
}
}
判斷是否取消了請求,如果是的就就直接抛出異常。
public final class RetryAndFollowUpInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
......
int followUpCount = 0;
Response priorResponse = null;
while (true) {
......
Response response;
boolean releaseConnection = true;
try {
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(), streamAllocation, false, request)) {
throw e.getFirstConnectException();
}
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, streamAllocation, requestSendStarted, request)) throw e;
releaseConnection = false;
continue;
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
······
}
}
}
循環處理請求。
- 嘗試着從責任鍊中擷取響應
,Response
- 如果出現異常
,RouteException
嘗試着去恢複,并繼續。IOException
public final class RetryAndFollowUpInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
......
int followUpCount = 0;
Response priorResponse = null;
while (true) {
......
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
......
}
}
}
如果上次的請求的
Response
不為
null
,添加到目前的
Response
中。
public final class RetryAndFollowUpInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
......
int followUpCount = 0;
Response priorResponse = null;
while (true) {
......
Request followUp;
try {
followUp = followUpRequest(response, streamAllocation.route());
} catch (IOException e) {
streamAllocation.release();
throw e;
}
if (followUp == null) {
streamAllocation.release();
return response;
}
......
}
}
}
調用
followUpRequest
擷取下次請求
Request
,
followUpRequest
中包括重定向,認證錯誤等處理。如果
followUp
為
null
說明不能進行下次重試或者重定向了,直接傳回。
public final class RetryAndFollowUpInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
......
int followUpCount = 0;
Response priorResponse = null;
while (true) {
......
closeQuietly(response.body());
if (++followUpCount > MAX_FOLLOW_UPS) {
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
if (followUp.body() instanceof UnrepeatableRequestBody) {
streamAllocation.release();
throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
}
if (!sameConnection(response, followUp.url())) {
streamAllocation.release();
streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(followUp.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
} else if (streamAllocation.codec() != null) {
throw new IllegalStateException("Closing the body of " + response
+ " didn't close its backing stream. Bad interceptor?");
}
request = followUp;
priorResponse = response;
}
}
}
先是關閉
response
的
body
。
接着就是判斷
followUpCount
是否超過了最大的
MAX_FOLLOW_UPS
,超過了直接抛出異常。
接着判斷
followUp
的
body
是否是
UnrepeatableRequestBody
的執行個體,如果是,直接抛出異常。
接着通過
sameConnection
方法判斷相應的
response
和
followUp
是否是同一個連接配接,如果是重定向二者不會相同,需要重新建立
StreamAllocation
最後是指派到相應的變量。繼續循環。