OKHttp3--拦截器链RealInterceptorChain源码解析【五】_没有鱼了的博客-CSDN博客
1. Interceptor概述
1:拦截器是OkHttp提供的一种强大的网络机制,它可以实现网络监听,请求已经响应重写,失败重连等。
2:在OkHttp中,我们发出的请求并不是直接连接到服务器获取结果,而是由OkHttp中的拦截器截获我们发出的请求,对请求进行观察,修改等操作,然后返回结果(这个机制就是:Android中拦截器模式)
3: 在OkHttp中,Interceptor是一个接口,它定义intercept(Chain chain) 函数来实现拦截功能
4:Chain 也是一个接口,具体实现类是: RealInterceptorChain , 这个接口有一个很重要的方法是:proceed(Request request) 函数, 当拦截器链开始工作时,取出第一个拦截器,并实例化一个新的拦截器,执行intercept() 方法,如果拦截器需要下一个拦截器获取响应,那就通过参数拿到拦截器链再次执行proceed() 方法,这里取出第二个拦截器,并继续调用该拦截器的 intercept方法,并以此类推,直到获取响应
2. RealInterceptorChain 概述
在OkHttp中不管时同步请求还是异步请求,最终都会走到 Real中的getResponseWithInterceptorChain() 方法,下面看看 RealCall.getResponseWithInterceptorChain源码
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));
// 这里需要构造 RealInterceptorChain对象
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
2.1 5个拦截器概述
RetryAndFollowUpInterceptor:网络请求失败时进行重定向及服务器返回当前请求需要进行重定向的拦截器
BridgeInterceptor : 桥连接器,主要时进行一些请求前的一些操作,能将我们的请求设置成服务器能识别的请求,比如设置一系列头部信息,设置请求内容的长度,编码,gzip压缩,cookie,AccessToken等
CacheInterceptor: 缓存拦截器,缓存请求和响应,比如如果从连接处能找到可复用的连接,就不要再创建新的连接
ConnectInterceptor :连接拦截器,为当前请求找到一个合适的连接,比如从连接处可以找到能复用的连接,就不要创建新的连接
CallServerInterceptor:连接服务器拦截器,服务向服务器发送真正的请求,接受服务器的响应。
2.2 RealInterceptorChain构造方法
我们再 getResponseWithInterceptorChain方法中,当拦截器组装完成后,就会实例化拦截器对象 RealInterceptorChain
Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest);
//拦截器列表,装载了所有拦截器
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;
//proceed方法执行次数
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;
}
2.3 RealInterceptorChain.proceed()方法
此方法核心就三行逻辑
实例化拦截器链 RealInterceptorChain, 但是要注意其中一个参数 index + 1 ,这样下一个拦截器链执行 proceed函数时,才能根据索引取出下一个拦截器,这就是拦击器链的概念
根据index 取出拦截器,因为index 每次都+1 ,所以就能根据拦截器列表添加的顺序取出拦截器,所以会依次取出
RetryAndFollowUpInterceptor BridgeInterceptor CacheInterceptor ConnectInterceptor ConnectInterceptor CallServerInterceptor xxxxInterceptor (程序员自己定义的拦截器)
执行拦截器的 intercept方法,并把实例化的 RealInterceptorChain 传入,这样每个拦截器再 intercept方法又能调用 RealInterceptorChain 的 proceed方法,并以此循环。
@Override
public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
/**
* 依次取出拦截器链表中的每个拦截器去获取Response
*/
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//如果索引值大于等于拦截器列表大小,就抛出异常,因为后续会出现数组越界的异常
if (index >= interceptors.size()) throw new AssertionError();
// 记录本方法调用次数
calls++;
// 如果已经为该Request创建了stream,就不再继续创建了
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");
}
// 如果已经为该Request创建了stream,那该方法只能调用一次
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// 创建新的拦截器链对象,并将index索引+1
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
//获取拦截器
Interceptor interceptor = interceptors.get(index);
//执行拦截器的intercept方法获取结果,并将新的拦截器链对象传入
Response response = interceptor.intercept(next);
// 确保该方法只能调用一次
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
return response;
}
3:拦截器总结
3.1 请查看我之前另一篇文章
设计模式之:责任链模式应用(Okhttp拦截器)_hongwen_yul的博客-CSDN博客
3.2 其实拦截器可以简单的理解就是 OkHttp中的一个网络请求,里面5 个拦截器依次执行自己的 intercept方法的过程
组装我们的请求对象 Request
调用下一个拦截器,获取 Response ,以此形成拦截器链
对Response进行处理,返回给上一个拦截器