okhttp拦截器采用责任链的设计模式,内置五层拦截器,并提供两种拦截器供用户插入链,类似压栈的结构,后进先出,最上层的可以处理最初始的request,也可以处理最终的response,上层拦截器通过调用chain.proceed(request)将事务传递给下一级的拦截器处理,这样一级一级的传递下去,直到最底层的拦截器处理完之后再将原始结果逐级返回
源码分析
我们去看一下内置的拦截器和用户定义的拦截器是如何组成一个链的,关键代码在RealCall
这个类中
final class RealCall implements Call {
//...去除无关代码
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
//可以看到内部使用一个ArrayList来维护
List<Interceptor> interceptors = new ArrayList<>();
//添加用户定义的ApplicationInterceptor 可能会有多个 interceptors.addAll(client.interceptors());
//添加重试重定向拦截器
interceptors.add(retryAndFollowUpInterceptor);
//添加桥接拦截器,这里传入了cookie参数
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//缓存拦截器
interceptors.add(new CacheInterceptor(client.internalCache()));
//连接管理拦截器
interceptors.add(new ConnectInterceptor(client));
//如果不是webSocket连接,则添加用户定义的networkInterceptors(可能会有多个)
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);
}
}
紧接着跟进RealInterceptorChain
这个类看下这个拦截器链式如何工作的
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//...一些check request /return代码 省略
//关键代码
// Call the next interceptor in the chain.
//构造下一个调用链
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
//执行下一个拦截器
Response response = interceptor.intercept(next);
//...一些check response /return代码 省略
return response;
}
- 通过上面这两段源码,拦截器链及其工作流程就非常的清晰了,关键流程在上面的注释中都分析过了,下面说下关于拦截器几个需要注意的点:
- ApplicationInterceptor是可以有多个的,多个会按顺序调用
- ApplicationInterceptor可以调用一次
chain.proceed(request)
,也可以调用多次,也可以一次都不调用,但必须返回response;这一点可以用来处理token失效自刷新,客户端http缓存等等 - networkInterceptor在每次重试或者重定向时都会重新调用,所以不建议在这里打印请求日志
- networkInterceptor在CacheInterceptor下级,所以可以修改本次resopnse中的header中缓存相关的参数,以便于CacheInterceptor来按我们的需求存储本次response
下面附上我自己总结的okhttp拦截器流程图
image
网友评论