OKHttp拦截器解析
OKHttp涉及到拦截器大概的执行步骤为:
1.通过newCall生成RealCall对象
具体代码如下:
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
2.调用Call的execute方法
当然这也可以是执行异步任务的enqueue方法,我们这里主要分析execute方法,在这个方法中调用getResponseWithInterceptorChain()从而调用拦截器。
具体代码如下:
/**
* 同步执行网络请求并返回响应
*
* @return 返回响应对象
* @throws IOException 如果在执行请求过程中发生I/O错误
*/
@Override public Response execute() throws IOException {
// 同步锁,确保同一时间只有一个线程执行该方法
synchronized (this) {
// 检查是否已经执行过,如果已经执行过则抛出异常
if (executed) throw new IllegalStateException("Already Executed");
// 标记为已执行
executed = true;
}
// 捕获调用栈信息,用于调试和错误追踪
captureCallStackTrace();
try {
// 将当前请求添加到调度器中,以便管理和执行
client.dispatcher().executed(this);
// 通过拦截器链获取响应
Response result = getResponseWithInterceptorChain();
// 如果响应为空,则抛出异常
if (result == null) throw new IOException("Canceled");
// 返回响应
return result;
} finally {
// 请求完成后,从调度器中移除当前请求
client.dispatcher().finished(this);
}
}
3.调用拦截器,处理相关拦截操作(责任链模式)
/**
* 通过拦截器链获取响应
*
* @return 返回响应对象
* @throws IOException 如果在获取响应过程中发生I/O错误
*/
Response getResponseWithInterceptorChain() throws IOException {
// 构建一个完整的拦截器栈
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));
// 如果不是WebSocket请求,添加网络拦截器
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
// 添加调用服务器拦截器,用于发送请求和接收响应
interceptors.add(new CallServerInterceptor(forWebSocket));
// 创建一个拦截器链
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
// 执行拦截器链并返回响应
return chain.proceed(originalRequest);
}
4.拦截器执行,链式调用
核心类为:RealInterceptorChain
public final class RealInterceptorChain implements Interceptor.Chain {
private final List<Interceptor> interceptors;
private final StreamAllocation streamAllocation;
private final HttpCodec httpCodec;
private final RealConnection connection;
private final int index;
private final Request request;
private int calls;
public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
HttpCodec httpCodec, RealConnection connection, int index, Request request) {
this.interceptors = interceptors;
this.connection = connection;
this.streamAllocation = streamAllocation;
this.httpCodec = httpCodec;
this.index = index;
this.request = request;
}
@Override public Connection connection() {
return connection;
}
public StreamAllocation streamAllocation() {
return streamAllocation;
}
public HttpCodec httpStream() {
return httpCodec;
}
@Override public Request request() {
return request;
}
// 这个是拦截器中执行的proceed方法
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
...
// Call the next interceptor in the chain.
// 传入下一个拦截器的索引和拦截器List,生成RealInterceptorChain对象
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
// 根据当前索引获取拦截器
Interceptor interceptor = interceptors.get(index);
// 我们的拦截器实现了intercept(chain)方法,通过intercept实现了调用拦截器链的操作
Response response = interceptor.intercept(next);
...
return response;
}
}
具体我们实现拦截器的简单例子如下:
public class CustomHeaderInterceptor implements Interceptor {
@Override
public Response intercept(Chain next) throws IOException {
Request originalRequest = next.request();
// 添加自定义头部信息
Request newRequest = originalRequest.newBuilder()
.header("Custom-Header", "Custom-Value")
.build();
// 继续处理请求,我们可以看到,Response response = interceptor.intercept(next)传下来的next在这里执行了proceed方法。从而实现了链式调用
return next.proceed(newRequest);
}
}