okhttp在发起网络请求过程中使用了拦截器机制,逐层对request和response做处理
// 关键方法
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors()); // 添加自定义拦截器,可以通过builder.addInterceptor()方法添加
interceptors.add(retryAndFollowUpInterceptor); // 重试、重定向拦截器
interceptors.add(new BridgeInterceptor(client.cookieJar())); // 编解码、压缩解压拦截器
interceptors.add(new CacheInterceptor(client.internalCache())); // 缓存拦截器
interceptors.add(new ConnectInterceptor(client)); // 复用连接池拦截器
if (!forWebSocket) { // forWebSocket默认为false
interceptors.addAll(client.networkInterceptors()); // 添加自定义拦截器,可以通过builder.addNetworkInterceptor()方法添加
}
interceptors.add(new CallServerInterceptor(forWebSocket)); // 最底层拦截器,真正访问服务端发起请求接收响应
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
okhttp中有两种拦截器:
- interceptors 处理应用层业务逻辑
- networkInterceptors 处理网络层逻辑
networkInterceptors在interceptors之后处理,如果前面的拦截器处理了请求直接返回结果,后面的拦截器就不会执行,例如CacheInterceptor中如果命中缓存,就不会再往下走。
添加完拦截器后,创建拦截链RealInterceptorChain,然后调用拦截链的proceed方法并返回方法执行结果。
创建RealInterceptorChain时传入的值说明:
- interceptors:传入保存了拦截器的List
- 0:索引,初始0。表示当前执行到第几层拦截器,通过它从interceptors取出拦截器执行
- originalRequest:我们创建的原始Request
下面分析RealInterceptorChain的proceed方法
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++; // 正常情况下这里执行完calls=1,用于校验拦截器是否只调用了一次proceed
// 第一次执行时,streamAllocation、httpCodec、connection都为null
// If we already have a stream, confirm that the incoming request will use it.
if (this.httpCodec != null && !this.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.httpCodec != 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, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout); // 新建一个拦截链,传入index+1
Interceptor interceptor = interceptors.get(index); // 取出当前索引的拦截器
Response response = interceptor.intercept(next); // 调用拦截器的intercept方法,并传入新的拦截链
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != 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;
}
这个方法的关键就是根据index取出拦截器,再调用拦截器的intercept方法并传入新的拦截链。
每个拦截器需要继承Interceptor接口实现intercept方法,在intercept方法中需要实现以下主要步骤
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request(); // 从chain中取出request
//todo 可以对request做修改或打印等扩展操作
···
//todo 判断如果满足某些条件直接返回response
if(checkHit()) {
return new Response.Builder().request(chain.request()).build();
}
//todo 执行拦截链的proceed方法,调用下一个拦截器,获取Response
Response response = chain.proceed(request);
//todo 可以对response做修改或打印等扩展操作
···
//todo 返回response给上一层
return response;
}
request经过拦截链层层拦截处理,最终到最底层的拦截器CallServerInterceptor,由它真正向服务端发起请求和获取响应,最后再将response层层往外传递给调用者。