前言
对于客户端来说,网络请求就是发送一个Request,得到一个Response的过程;很多的网络请求框架都会对这个过程进行封装处理,减少我们对内部逻辑的了解以及用少量的代码完成整个请求流程。不同公司的网络请求定义格式不一样,就需要我们的网络请求框架能够更灵活的扩展,从而在不改变源码的情况下,完成业务的需求。比如在请求过程,对请求的数据统一加解密处理,不同的业务,设置不同的Header,日志拦截等等。对OKHttp而言,就很好的考虑到这些需求,对Request和Response提供了责任链的模式的Interceptor供我们开发中灵活扩展,其中一些必须的Interceptor已经在内部实现,自动添加。下面就了解OKHttp是如何实现这种灵活扩展的。
OkHttp的Request和Response简易流程
OkHttpClient okHttpClient = new OkHttpClient();
String url = "https://publicobject.com/helloworld.txt";
Request request = new Request.Builder()
.url(url)
.build();
Response response = okHttpClient.newCall(request).execute();
这里的示例代码说了客户如何发送一个Request和得到一个Response的流程,使用起来很简单,内部的实现细节和流程OkHttp已往我们完成。下面看一下源码的RealCall的execute()方法做了哪些操作。
@Override
public Response execute() throws IOException {
...省略部分代码...
try {
client.dispatcher().executed(this);
//此处返回Response
return getResponseWithInterceptorChain();
} finally {
client.dispatcher().finished(this);
}
}
接下来看一下getResponseWithInterceptorChain()做了哪些操作:
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
//添加自定义的Intercepttor
interceptors.addAll(client.interceptors());
//添加系统内部的Interceptor,统一添加到List中
interceptors.add(new RetryAndFollowUpInterceptor(client));
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, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
//获取Response
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
这里的Response是通过RealInterceptorChain的procedd()方法返回的,接下来看一下chain的proceed()方法做了哪些操作。
@Override public Response proceed(Request request) throws IOException {
return proceed(request, transmitter, exchange);
}
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException {
...省略部分代码...
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
//获取拦截器
Interceptor interceptor = interceptors.get(index);
//调用拦截器的intercept方法进行处理
Response response = interceptor.intercept(next);
....省略部分代码...
return response;
}
这里已经出现了Interceptor和Chain的影子,接下来了解具体的实现过程。
Intercptor和Chain在OkHttp中的内部实现
Interptor和Chain的内部定义,这里对Interceptor的描述主要意思是可以对Request和Response进行处理。
/**
* 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;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
...省略部分代码...
}
}
从发出一个Request到得到一个Response,中间都需要经过一些处理,完成Http协议的相关内容设置,最终再由Socket的OutputStream和InputStream完成读写,完成整个流程。这些中间层的处理由相应Interceptor来完成,让代码结构更新清晰,同时也满足了我们的单一职责原则。比如:RetryAndFollowUpInterceptor,负责完成重试机制;BridgeInterceptor,完成Http协议中一些默认Header的添加;CacheInterceptor,处理我们的请求可以拿缓存数据还是需要从服务拉取数据;ConnectInterceptor,负责处理请求的Connection;CallServerInterceptor,负责最终与服务端的交互处理。从发出一个Request到返回Response,则需要完成一个链式的调用流程,将相关的Interceptor组成一条链,再后RealInterceptorChain来完成责任链的流程。因此Request到Response的设计采用责任链的模式更合理和更加容易灵活扩展。
下面给出一个Chain的处理图:
接下来看一下内部是如何完成链式调用流程的,在ReallCall的getResponseWithInterceptorChain()方法中,初始化RealInterceptorChain,默认处理List中的第0个
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
.......
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
try {
//处理请求
Response response = chain.proceed(originalRequest);
}
...省略部分代码...
}
接下来看chain.procced()的内部实现
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException {
...省略部分代码...
// Call the next interceptor in the chain.
//实例化一个新的RealInterceptorChain,index+1指向下一个Interceptor
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
//取出当前Interceptor,并调用其对应的intercept()方法。
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
...省略部分代码...
return response;
}
这里我们不添加自定义Interceptor的情况下,List中包含了Intercptor依次为RetryAndFollowUpInterceptor,BridgeInterceptor,CacheInterceptor,ConnectInterceptor,CallServerInterceptor。在getResponseWithInterceptorChain()方法中,index为0,因此取出的第一个Interceptor为RetryAndFollowUpInterceptor,同时实例化指向下一个Interceptor的的chain。我们看一下RetryAndFollowUpInterceptor的interceptor做了什么操作:
public final class RetryAndFollowUpInterceptor implements Interceptor {
......
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
...省略部分代码...
while (true) {
......
Response response;
boolean success = false;
try {
//调用chain.proceed方法,执行下一个Interceptor
response = realChain.proceed(request, transmitter, null);
success = true;
}
......
}
}
}
在RetryAndFollowUpInterceptor的intercept()方法中调用RealInterceptorChain.procced方法,紧接着执行BridgeInterceptor的intercept()方法
public final class BridgeInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder
......
//调用chain.proceed方法,执行下一个Interceptor
Response networkResponse = chain.proceed(requestBuilder.build());
......
}
}
其他的Interceptor的处理类似,这里面能够直接返回Response的分别是CacheInterceptor和CallServerInterceptor,在CacheInterceptor中,如果符合要求,可直接返回cacheResponse,不在执行 chain.proceed()方法,否则,继续执行后面的Interceptor,最终执行到CallServerInterceptor,请求服务器获取数据,返回Response。
OkHttp中的Chain的用法和我们和经典的责任链模式的使用方法略有不同。在经典责任链模式中,我需要手动设置nextHandler;在OkHttp中,我们只需要将Interceptor添加到OkHttpClient中,由内部帮我们维护责任链的上下连接关系。这里具体在RealInterceptorChain的proceed()方法中处理。
对于网络来讲,Request在链中是一种平级关系,每个Interceptor都可以根据自己的需要对Request处理,拿到Response后更具需要进行处理后,再将Response返回给上一个Interceptor。
小结
-
OkHttp中Interceptor的灵活设计,使得我们可以在不修改源码的基础上对Request和Response进行很多灵活处理,比如日志输出,可用添加自定义LogInterceptor;双Token的刷新可以添加自定义的RefreshInterceptor;项目中不同的请求使用不同的地址,可自定义DomainInterceptor等等。
-
OkHttp中责任链模式的设计与经典责任链模式的不同,可以减少我们在自定义Interceptor时由于对内部原理不熟悉的情况下犯错误的可能。