看一下OkHttp内置的第一个拦截器RetryAndFollowUpInterceptor:
RetryAndFollowUpInterceptor
public final class RetryAndFollowUpInterceptor implements Interceptor {
private static final int MAX_FOLLOW_UPS = 20; //最大的重定向次数
private final OkHttpClient client; //前面创建的OkHttpClient对象
private final boolean forWebSocket; //是否是webSocket
private StreamAllocation streamAllocation; //流分配器,在这个拦截器中初始化
private Object callStackTrace;
private volatile boolean canceled; //请求是否被取消了
//主要是传入进来OkHttpClient对象
public RetryAndFollowUpInterceptor(OkHttpClient client, boolean forWebSocket) {
this.client = client;
this.forWebSocket = forWebSocket;
}
@Override public Response intercept(Chain chain) throws IOException {
//***************获取需要的对象Request,RealInterceptorChain,Call,StreamAllocation****************
Request request = chain.request(); //之前我们创建的Request对象
RealInterceptorChain realChain = (RealInterceptorChain) chain;//创建的下一个拦截器链
Call call = realChain.call(); //我们之前创建的RealCall
EventListener eventListener = realChain.eventListener();
//创建了一个StreamAllocation对象,持有全局的连接池,Address对象,Call对象
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 {
//**************开始进行请求*************************************************************
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();
}
}
// 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();
}
//**********************解析回复的code,如果请求失败,进行重定向*******************
//解析response的code,判断response的类型,看是否请求成功。
Request followUp = followUpRequest(response);
//如果请求成功,返回followUp Request为null
if (followUp == null) {
if (!forWebSocket) {
streamAllocation.release();
}
//请求成功,返回这个response
return response;
}
//请求不成功,这个response关闭,释放资源。
closeQuietly(response.body());
//followUpCount加1后判断是否大于MAX_FOLLOW_UPS
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());
}
//看response的服务器地址和followUp Request的url对比,看地址是否相同,这涉及是否可以连接复用。
if (!sameConnection(response, followUp.url())) {
streamAllocation.release();
//重新创建一个StreamAllocation对象
streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(followUp.url()), call, eventListener, callStackTrace);
} else if (streamAllocation.codec() != null) {
throw new IllegalStateException("Closing the body of " + response
+ " didn't close its backing stream. Bad interceptor?");
}
//重新赋值Request对象
request = followUp;
//记录Response
priorResponse = response;
}
/**
* 取消执行请求
*/
public void cancel() {
canceled = true;
StreamAllocation streamAllocation = this.streamAllocation;
if (streamAllocation != null) streamAllocation.cancel();
}
//返回是否被取消
public boolean isCanceled() {
return canceled;
}
}
上述过程中出现了StreamAllocation对象的创建,以及调用release方法等。下面看一下StreamAllocation这个类:
StreamAllocation
public final class StreamAllocation {
public final Address address; //请求地址信息
private RouteSelector.Selection routeSelection;//路由选择器
private Route route; //路由
private final ConnectionPool connectionPool; //全局连接池,在OkHttpClient对象创建过程中已经创建完成
public final Call call; //请求Call
public final EventListener eventListener;
private final Object callStackTrace;
// State guarded by connectionPool.
private final RouteSelector routeSelector;
private int refusedStreamCount;
private RealConnection connection; //真实建立的连接
private boolean reportedAcquired;
private boolean released; //资源是否被释放
private boolean canceled; //请求是否被取消
private HttpCodec codec; //Http 流
public StreamAllocation(ConnectionPool connectionPool, Address address, Call call,
EventListener eventListener, Object callStackTrace) {
this.connectionPool = connectionPool;
this.address = address;
this.call = call;
this.eventListener = eventListener;
this.routeSelector = new RouteSelector(address, routeDatabase(), call, eventListener);
this.callStackTrace = callStackTrace;
}
//释放资源
public void release() {
Socket socket;
Connection releasedConnection;
synchronized (connectionPool) {
releasedConnection = connection;
socket = deallocate(false, true, false);//会关闭connection对象
if (connection != null) releasedConnection = null;
}
closeQuietly(socket);
if (releasedConnection != null) {
eventListener.connectionReleased(call, releasedConnection);
}
}
}
后续会针对StreamAllocation专门进行更深入的介绍。
重定向功能是否开启,在创建OkHttpClient的时候可以设置:
new OkHttpClient().newBuilder()
.followRedirects(false) //禁制OkHttp的重定向操作,我们自己处理重定向
.followSslRedirects(false)//https的重定向也自己处理
简单进行流程总结: