拦截器的工作原理
在okhttp
中拦截器是一个重要的概念,而拦截器中最重要的就是链
的概念之后,会以这点为核心作出解析。okhttp
的日常使用中我们经常都需要对拦截器进行一些重写操作,来满足我们在项目中的需求。常用的interceptor
和networkInterceptor
,但这里我们暂时不去了解它,在RealCall的execute()中执行了这段代码:
Response response = getResponseWithInterceptorChain();
在请求中通过getResponseWithInterceptorChain拦截器链
最终得到返回Response
,下面就一步一步的来看看我们是怎么通过拦截器最终获得的这个response
:
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);
return chain.proceed(originalRequest);
}
- 首先创建集合来添加各种拦截器
- 创建
RealInterceptorChain
拦截器链(这里链的概念在拦截器中运用的很深刻)并执行它的proceed
方法:
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// 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);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// 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");
}
return response;
}
在proceed中代码较多最主要的将它提出来:
if (index >= interceptors.size()) throw new AssertionError();
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
return response;
- 创建
RealInterceptorChain
并且下标为index+1
(getResponseWithInterceptorChain()中才创建了一个),index是上一个RealInterceptorChain通过构造器传递下来的 - 通过下标获取到inercepter调用
intercept(next)
方法获取到Response并返回。看看 interceptor.intercept(next)接口,实际上就是在此调用它的实现类并通过intercept(Chain chain)得到的Response并返回上一级:
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
- 这样一级一级的调用什么时候算完了呢?其实在上面的代码中,第一段
if (index >= interceptors.size()) throw new AssertionError()
就判断了,当下标大于拦截器数量时就抛出异常停止下一级调用了。
就这样拦截器实现了链式调用,使我们一直往下调用拦截器链并通过当前拦截器interceptor.intercept(next)
获得response返回给上一个拦截器。这样我们就把所有拦截器都执行完毕,这也是okhttp拦截器的核心逻辑,也是我们如何一步一步获取到接口的返回i
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
这里是 RetryAndFollowUpInterceptor
的intercept方法中一行代码补充我们上面所得到的结论
总结
- 先创建拦截器集合
- 将集合放
拦截器链
中执行它的processd()方法 - 在processd()中执行拦截器的通过下标获得此次intercetpor
- 调用intercepter(Chain chain)方法返回Response并再次执行下一级拦截器链的processd()方法形成链式调用,最终获得一个完整的返回