主要流程篇 OkHttp源码相关(一) 。
拦截器篇 OkHttp源码相关(二) 。
1.责任链模式
说到拦截器就不得不提一下他的设计模式:责任链模式为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。在责任链模式中,每一个对象对其下家的引用而接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的 情况下动态的重新组织链和分配责任。处理者有两个选择:承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。
看文字有点蒙蔽,我们看下图, 如果我发起一个请求request,那么这个责任链模式下就会一层层的去调用处理我这个request,当最后一层处理完毕以后又会一层层的返回response返回值,最后返回到发起者这里,这就是责任链模式。当然也有可能我发起的request并没有返回的response,而是在某一层就被符合条件的interceptor给处理掉了,也是符合责任链模式的。
2.五大拦截器
拦截器就是用到了刚才说的责任链模式
-
RetryAndFollowUpInterceptor
重试拦截器在交出(交给下一个拦截器)之前,负责判断用户是否取消了请求;在获得了结果之后,会根据响应码判断是否需要重定向,如果满足条件那么就会重启执行所有拦截器。第一个接触到请求,最后接触到响应;负责判断是否需要重新发起整个请求。 -
BridgeInterceptor
桥接拦截器在交出之前,负责将HTTP协议必备的请求头加入其中(如:Host,Content-Type,Keep-Alive等,其实就是方便用户,省了用户自己加了)并添加一些默认的行为(如:GZIP压缩);在获得了结果后,调用保存cookie接口并解析GZIP数据。 补全请求,并对响应进行额外处理。 -
CacheInterceptor
缓存拦截器交出之前读取并判断是否使用缓存;获得结果后判断是否缓存。请求前查询缓存,获得响应并判断是否需要缓存,主要是看networkRequest与cacheResponse着两个
@Override public Response intercept(Chain chain) throws IOException {
//1 尝试通过url的md5数据从文件缓存查找(get方法)
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
//2 如果不允许使用网络并且缓存为空,Resposne返回504,啥也不让搞就gg了
if (networkRequest == null && cacheResponse == null) {
return new Response;
}
//3 如果不允许使用网络,但是有缓存,返回缓存。
if (networkRequest == null) {
return cacheResponse;
}
//4 调用下一个拦截器
networkResponse = chain.proceed(networkRequest);
//5 如果缓存不为空,但是网络请求得来的返回码是304(无修改的),则更新缓存的响应
if (cacheResponse != null) {
if (networkResponse.code() == HTTP_NOT_MODIFIED) {
Response response = cacheResponse.newBuilder()
return response;
}
}
//6 使用网络请求得到的Resposne,并且将这个Resposne缓存起来
Response response = networkResponse;
cache.put(response);
return response;
}
networkRequest存在则优先发起网络请求,否则使用cacheResponse缓存,若都不存在则请求失败。
-
ConnectInterceptor
连接拦截器在交出之前,负责找到或者新建一个连接,并获得对应的socket流;在获得结果后不进行额外的处理。与服务器完成TCP连接。主要是负责连接池socket连接的复用(判断连接是否可用,不可用则从ConnectionPool获取连接,ConnectionPool无连接,创建新连接,握手,放入ConnectionPool,最多缓存5个,每个5分钟,超时无使用释放)、代理连接相关, -
CallServerInterceptor
请求服务器拦截器进行真正的与服务器的通信,向服务器发送数据,解析读取的响应数据。
与服务器通信;封装请求数据与解析响应数据(如:HTTP报文)
在 Response response = getResponseWithInterceptorChain();这个方法里调用了这些拦截器
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List 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);
}
具体看一下拦截器是如何用责任链模式实现的
首先是在一个集合里add进去了这些拦截器,然后把集合放进RealInterceptorChain方法里,并调用proceed方法。注意这里RealInterceptorChain的参数0,然后看下procee的方法,这里对我们之前传过来的0会开始累积了
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
.....
// 创建新的拦截链,链中的拦截器集合index+1
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
//执行当前的拦截器 默认是:retryAndFollowUpInterceptor
Interceptor interceptor = interceptors.get(index);
//执行当前拦截器intercept方法
Response response = interceptor.intercept(next);
......
return response;
}
创建RealInterceptorChain并且下标为index+1(getResponseWithInterceptorChain()中才创建了一个),index是上一个RealInterceptorChain通过构造器传递下来的。这里主要是看一下Interceptor这个接口,每个拦截器都继承了Interceptor接口,在RealInterceptorChain方法里开始调用。
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
我们看第一个retryAndFollowUpInterceptor方法里,执行到一半,又去执行了RealInterceptorChain中的proceed方法,这就是递归调用了,RealInterceptorChain这个方法会被每个拦截器调用,然后里边的index+1去执行下一个拦截器。
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// 首先拿到当前真实的Interceptor 实现类
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Call call = realChain.call();
EventListener eventListener = realChain.eventListener();
// 核心 协调连接、请求/响应以及复用
StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(request.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
int followUpCount = 0;
Response priorResponse = null;
while (true) {
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
//又执行了RealInterceptorChain中的proceed方法
//实际上就是下一个拦截器
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
.....
}
}
当最后一个拦截器调用完成后,就会返回Response结果了。
总的来说就是先创建拦截器集合,然后将集合放拦截器链中执行它的processd()方法,在processd()中通过下标获得此次intercetpor,调用intercepter(Chain chain)方法并再次执行下一级拦截器链的processd()方法形成链式调用,当最后一个返回Response之后,会按传过来的顺序再把Response逐渐返回去,最终获得一个完整的调用。