一、各个拦截器的作用
1.RetryAndFollowUpInterceptor负责对失败的链接在合适的情况下进行重定向
2.BridgeInterceptor负责构建客户端请求为服务器需要的格式
3.CacheInterceptor负责读取缓存中的请求
二、RetryAndFollowUpInterceptor
1.将请求路径封装成streamAllocation
2.proceed会执行后续拦截器实现真正的网络请求,如果异常,会通过recover检查是否可以恢复
3.followup方法接收服务端的响应后检查是否满足重定向的需求
4.如果满足会重新根据返回的请求解析出url,重新构建一个请求包装成streamAllocation,满足重定向的错误码(300,301,302,303)
while (true) {
.....
Response response = null;
boolean releaseConnection = true;
try {
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
releaseConnection = false;
}
.....
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();
}
}
// 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();
}
//检查是否需要重定向
Request followUp = followUpRequest(response);
if (followUp == null) {
if (!forWebSocket) {
streamAllocation.release();
}
return response;
}
closeQuietly(response.body());
//重定向的次数不能超过20次
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());
}
//确保构建出来的不是同一个connect,再次请求一遍同样的connect仍然会失败
if (!sameConnection(response, followUp.url())) {
streamAllocation.release();
streamAllocation = new StreamAllocation(
client.connectionPool(), createAddress(followUp.url()), callStackTrace);
} 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;
}
}
根据端口,协议,路径来判断是否为同一个请求
//scheme:http或https
private boolean sameConnection(Response response, HttpUrl followUp) {
HttpUrl url = response.request().url();
return url.host().equals(followUp.host())
&& url.port() == followUp.port()
&& url.scheme().equals(followUp.scheme());
}
网友评论