OkHttp 最精髓的地方就是它的拦截器,把网络请求的操作解耦,每个拦截器只负责自己的工作,并且可以根据自己的需求自定义添加拦截器。第一次看到拦截器那段代码我是懵逼的。
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
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));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
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);
}
乍一看,就是把一堆拦截器添加到了列表中,然后 new 了一个 Chain 对象启动了一下,这就构成了可以拦截请求拦截响应的拦截器链吗?翻看源码发现主要是通过递归调用函数栈来实现这种往下拦截请求,往上拦截响应的。
我模仿源码拦截器写了一段伪代码方便理解拦截器的工作流程。
首先定义拦截器接口和连接拦截器的锁链接口。
public interface MyInterceptor {
/**
* 拦截
*
* @param chain 下一个锁链
*/
String intercept(MyChain chain);
interface MyChain {
/**
* 获取请求
*/
String request();
/**
* 处理请求返回一个结果
*/
String process(String request);
}
}
A、B、C 三个拦截器的实现,各自拦截请求和响应
public class InterceptorA implements MyInterceptor {
@Override public String intercept(MyChain chain) {
// 修改请求
String request = chain.request();
String newRequest = request + "/a";
Log.d("InterceptorA", "newRequest = " + newRequest);
// 调用第2个链子处理新的请求,返回处理后的结果
String response = chain.process(newRequest) + "/responseA";
Log.d("InterceptorA", "response = " + response);
return response;
}
}
public class InterceptorB implements MyInterceptor {
@Override public String intercept(MyChain chain) {
// 修改请求
String request = chain.request();
String newRequest = request + "/b";
Log.d("InterceptorB", "newRequest = " + newRequest);
// 处理请求
String response = chain.process(newRequest) + "/responseB";
Log.d("InterceptorB", "response = " + response);
return response;
}
}
public class InterceptorC implements MyInterceptor {
@Override public String intercept(MyChain chain) {
// 修改请求
String request = chain.request();
String newRequest = request + "/c";
Log.d("InterceptorC", "newRequest = " + newRequest);
// 处理请求
String response = chain.process(newRequest) + "/responseC";
Log.d("InterceptorC", "response = " + response);
return response;
}
}
锁链的实现:
public class RealChain implements MyInterceptor.MyChain {
private final String request;
private final int index;
private final List<MyInterceptor> interceptors;
public RealChain(String request, int index, List<MyInterceptor> interceptors) {
this.request = request;
this.index = index;
this.interceptors = interceptors;
}
@Override public String request() {
return request;
}
@Override public String process(String request) {
if (index == interceptors.size()) {
return "请求结束,得到结果:";
}
// 构建下一个锁链实例,处理下一个拦截器
RealChain next = new RealChain(request, index + 1, interceptors);
// 得到当前的拦截器
MyInterceptor interceptor = interceptors.get(index);
// 当前拦截器进行拦截得到处理结果,将结果返回
return interceptor.intercept(next);
}
}
关键是调用的时候,从第一个锁链开始往下递归依次调用拦截器的拦截方,按 A ->B->C 的顺序拦截请求。调用到最后一个拦截器时开始往回按 C->B->A 返回结果,这样就构成了官方拦截器图的效果。
String getMyInterceptorChain() {
List<MyInterceptor> interceptors = new ArrayList<>();
interceptors.add(new InterceptorA());
interceptors.add(new InterceptorB());
interceptors.add(new InterceptorC());
String originRequest = "www.baidu.com";
// 构建出锁链
RealChain chain = new RealChain(originRequest, 0, interceptors);
return chain.process(originRequest);
}
运行后打印日志,请求是按ABC的顺序拦截添加的,返回结果则是CBA的顺序拦截添加的。
newRequest = www.baidu.com/a
newRequest = www.baidu.com/a/b
newRequest = www.baidu.com/a/b/c
response = 请求结束,得到结果:/responseC
response = 请求结束,得到结果:/responseC/responseB
response = 请求结束,得到结果:/responseC/responseB/responseA
函数调用顺序:
链子A处理 -> 拦截器A拦截 -> 链子B处理 -> 拦截器B拦截 -> 链子C处理 -> 拦截器C拦截 -> 链子C处理 -> end