okhttp攔截器采用責(zé)任鏈的設(shè)計(jì)模式,內(nèi)置五層攔截器,并提供兩種攔截器供用戶插入鏈,類似壓棧的結(jié)構(gòu),后進(jìn)先出,最上層的可以處理最初始的request,也可以處理最終的response,上層攔截器通過調(diào)用chain.proceed(request)將事務(wù)傳遞給下一級(jí)的攔截器處理,這樣一級(jí)一級(jí)的傳遞下去,直到最底層的攔截器處理完之后再將原始結(jié)果逐級(jí)返回
源碼分析
我們?nèi)タ匆幌聝?nèi)置的攔截器和用戶定義的攔截器是如何組成一個(gè)鏈的,關(guān)鍵代碼在RealCall這個(gè)類中
final class RealCall implements Call {
//...去除無關(guān)代碼
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
//可以看到內(nèi)部使用一個(gè)ArrayList來維護(hù)
List<Interceptor> interceptors = new ArrayList<>();
//添加用戶定義的ApplicationInterceptor 可能會(huì)有多個(gè) interceptors.addAll(client.interceptors());
//添加重試重定向攔截器
interceptors.add(retryAndFollowUpInterceptor);
//添加橋接攔截器,這里傳入了cookie參數(shù)
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//緩存攔截器
interceptors.add(new CacheInterceptor(client.internalCache()));
//連接管理攔截器
interceptors.add(new ConnectInterceptor(client));
//如果不是webSocket連接,則添加用戶定義的networkInterceptors(可能會(huì)有多個(gè))
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
//添加調(diào)用服務(wù)攔截器
interceptors.add(new CallServerInterceptor(forWebSocket));
//組成鏈條
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//在鏈上開始執(zhí)行事務(wù)
return chain.proceed(originalRequest);
}
}
緊接著跟進(jìn)RealInterceptorChain這個(gè)類看下這個(gè)攔截器鏈?zhǔn)饺绾喂ぷ鞯?/p>
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//...一些check request /return代碼 省略
//關(guān)鍵代碼
// Call the next interceptor in the chain.
//構(gòu)造下一個(gè)調(diào)用鏈
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
//執(zhí)行下一個(gè)攔截器
Response response = interceptor.intercept(next);
//...一些check response /return代碼 省略
return response;
}
- 通過上面這兩段源碼,攔截器鏈及其工作流程就非常的清晰了,關(guān)鍵流程在上面的注釋中都分析過了,下面說下關(guān)于攔截器幾個(gè)需要注意的點(diǎn):
- ApplicationInterceptor是可以有多個(gè)的,多個(gè)會(huì)按順序調(diào)用
- ApplicationInterceptor可以調(diào)用一次
chain.proceed(request),也可以調(diào)用多次,也可以一次都不調(diào)用,但必須返回response;這一點(diǎn)可以用來處理token失效自刷新,客戶端http緩存等等 - networkInterceptor在每次重試或者重定向時(shí)都會(huì)重新調(diào)用,所以不建議在這里打印請(qǐng)求日志
- networkInterceptor在CacheInterceptor下級(jí),所以可以修改本次resopnse中的header中緩存相關(guān)的參數(shù),以便于CacheInterceptor來按我們的需求存儲(chǔ)本次response
下面附上我自己總結(jié)的okhttp攔截器流程圖

image