同步异步源码解读的传送门https://www.jianshu.com/p/baf47f6f0e11
OkHttp网络请求的重中之重拦截器链,在官方文档中是这样解释的:
拦截器是OkHttp中提供的一种强大机制,它可以实现网络监听、请求以及响应重写、请求失败重试等功能。
PS:拦截器是不区分同步和异步的
下面这是官网的图:
一种是系统应用的拦截器,一种是网络拦截器,这里我们只谈OkHttp内部系统的拦截器,总共分为5种。如下图所示:
image.png
我们再回到RealCall这个类中,看看同步和异步最终执行的方法:
同步:
@Override public Response execute() throws IOException {
synchronized (this) { // 加同步锁
// 同一个http请求只能执行一次,执行完就设置为你true
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
timeout.enter();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
e = timeoutExit(e);
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
异步:
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
// 和同步一样判断是否请求过这个链接,已经请求过就直接抛出异常
if (executed) throw new IllegalStateException("Already Executed");
executed = true; // 请求过就设置为true
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback)); // 关键代码
}
异步线程真实执行的方法:
// 这个方法才是线程真正实现的方法,在父类NamedRunnable中是一个抽象的方法,在线程的run方法中实现的
@Override protected void execute() { // 这个方法是在子线程中操作的
boolean signalledCallback = false;
timeout.enter();
try {
Response response = getResponseWithInterceptorChain(); // 拦截器链
if (retryAndFollowUpInterceptor.isCanceled()) { // 重定向和重试的拦截器是否取消了
signalledCallback = true;
// 如果取消了,就回掉返回失败给用户
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
// 没取消重定向拦截器就正常返回数据
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
e = timeoutExit(e);
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
/**
* 这个finish做的事情
* 1.把这个请求从正在请求的队列中删除
* 2.调整我们整个异步请求的队列,因为这个队列是非线程安全的
* 3.重新调整异步请求的数量
*/
client.dispatcher().finished(this);
}
}
}
从上面看出,不管是同步还是异步都使用了拦截器链,返回Response 对象
下面我们来看看getResponseWithInterceptorChain()这个方法:
// 所使用的拦截器链 在官网上分为两个拦截器 Application 应用拦截器和NetWork网络拦截器
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); // 拦截后调用proceed方法来执行相应请求
}
从代码中可以看出,是一个List集合依次添加用户自定义的拦截器和OkHttp内部的一系列拦截器,到最后通过RealInterceptorChain对象创建出一个拦截器链Interceptor.Chain来,拦截器链执行chain.proceed方法。我们跟着这个方法走进去到RealInterceptorChain类中,对应的方法:
@Override
public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
最终到这个方法中:
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. 核心方法实现 就是创建下一个拦截器链
/**
* 创建了一个拦截器的链,这个链和刚才前面讲的链的区别 ,传入的参数是index + 1,意思就是如果我们下面
* 要访问的话,只能从下一个拦截器访问,不能从当前拦截器访问,这就形成了一个拦截器链
*/
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); // 再把上面获取到的拦截器链,当做参数传进去,这样就形成了所有拦截器的链条
// 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;
}
这里面的核心在上面代码中已经写明,这里就不在阐述了。
所有的拦截器都实现了Interceptor这个接口:
/**
* Observes, modifies, and potentially short-circuits requests going out and the corresponding
* responses coming back in. Typically interceptors add, remove, or transform headers on the request
* or response.
*/
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
// 也就是说我们可以通过实现Interceptor,定义一个拦截器对象,然后拿到请求和Response对象,对Request和Response进行修改
interface Chain {
// 实现chain接口对象的request方法可以拿到Request对象
okhttp3.Request request();
// 实现chain接口对象的proceed方法可以拿到Response对象
Response proceed(Request request) throws IOException;
/**
* Returns the connection the request will be executed on. This is only available in the chains
* of network interceptors; for application interceptors this is always null.
*
* 返回将在其上执行请求的连接。这只适用于链条对于网络拦截器;对于应用程序拦截器,此值始终为空
*/
@Nullable
Connection connection();
Call call();
int connectTimeoutMillis();
Chain withConnectTimeout(int timeout, TimeUnit unit);
int readTimeoutMillis();
Chain withReadTimeout(int timeout, TimeUnit unit);
int writeTimeoutMillis();
Chain withWriteTimeout(int timeout, TimeUnit unit);
}
}
其实整个OkHttpde 请求就是经过这一个个的拦截器链的chain.proceed方法完成的。
我们来简单做个总结:
1.创建一系列拦截器,并将其放入一个拦截器list中。
2.创建一个拦截器链RealInterceptorChain,并执行拦截器链的proceed方法。
3.在发起请求前对request进行处理。
4.调用下一个拦截器,获取Response。
5.对Response进行处理,返回给上一个拦截器。
我们这里完全可以自定义拦截器,实现Interceptor,生成一个拦截器对象,然后拿到请求Request对象和响应Response对象,对Request和Response进行修改。
整个流程就是OkHttp通过定义许多拦截器一步一步地对Request进行拦截处理(从头至尾),直到请求返回网络数据,后面又倒过来,一步一步地对Response进行拦截处理,最后拦截的结果就是回调给调用者的最终Response。(从尾至头)
上一张图很清晰的理清拦截器的操作:
image.png
这篇先到这里,下一篇我们把OkHttp中的这5个拦截器一一细细分析。
感谢观看,如有错误,欢迎指正。
OkHttp的重定向及重试拦截器的源码解读:https://www.jianshu.com/p/d70f07288afc
网友评论