在 Okhttp源碼學(xué)習(xí)一(基本請(qǐng)求流程)中,只是學(xué)習(xí)了okhttp請(qǐng)求網(wǎng)絡(luò)的一個(gè)基本流程,但是最關(guān)鍵的點(diǎn),同步或異步請(qǐng)求過(guò)程中的第二步:執(zhí)行網(wǎng)絡(luò)請(qǐng)求,拿到響應(yīng)結(jié)果,這一步還沒(méi)有具體分析. okhttp的具體請(qǐng)求過(guò)程被封裝在內(nèi)置的攔截器中,所以本篇就先學(xué)習(xí)okhttp攔截器的工作過(guò)程
okhttp不管是同步還是異步請(qǐng)求,他們請(qǐng)求網(wǎng)絡(luò)的核心步驟都是一樣的,都會(huì)去調(diào)用 Response response = getResponseWithInterceptorChain()這一行代碼,這一行代碼就封裝了okhttp請(qǐng)求網(wǎng)絡(luò)的具體實(shí)現(xiàn),看一下它的源碼:
//RealCall.getResponseWithInterceptorChain
Response getResponseWithInterceptorChain() throws IOException {
// 攔截器集合,包括我們自定義的,okhttp內(nèi)置的
List<Interceptor> interceptors = new ArrayList<>();
//添加我們?cè)跇?gòu)建OkhttpClient對(duì)象時(shí),通過(guò)okhttpClient.builder添加的自定義攔截器
interceptors.addAll(client.interceptors());
//取消或失敗重試,重定向
interceptors.add(retryAndFollowUpInterceptor);
//橋接,連接用戶請(qǐng)求信息和 HTTP 請(qǐng)求的橋梁(把用戶構(gòu)造的請(qǐng)求轉(zhuǎn)換為發(fā)送到服務(wù)器的請(qǐng)求)
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//緩存
interceptors.add(new CacheInterceptor(client.internalCache()));
//連接
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
//網(wǎng)絡(luò)請(qǐng)求
interceptors.add(new CallServerInterceptor(forWebSocket));
//創(chuàng)建一個(gè)攔截器鏈,將前面的攔截器列表作為參數(shù)傳入
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//開始請(qǐng)求
return chain.proceed(originalRequest);
}
getResponseWithInterceptorChain()是定義在RealCall里面的,可以看到如果我們不添加任何自定義攔截器的話,okhttp默認(rèn)就有5個(gè)內(nèi)置的攔截器:
RetryAndFollowUpInterceptor,BridgeInterceptor,CacheInterceptor,ConnectInterceptor,CallServerInterceptor.
getResponseWithInterceptorChain()要注意的一點(diǎn)是:
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
在創(chuàng)建RealInterceptorChain對(duì)象的時(shí)候,RealInterceptorChain的構(gòu)造函數(shù)的第5個(gè)參數(shù)index,可以看到傳入的是0,這個(gè)參數(shù)非常重要,后面會(huì)用到。getResponseWithInterceptorChain()最后調(diào)用了chain.proceed()
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
@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);
}
}
Chain是 Interceptor接口的內(nèi)部接口,RealInterceptorChain實(shí)現(xiàn)了 Interceptor.Chain接口,所以直接看RealInterceptorChain的Chain()方法:
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
.....
//又重新創(chuàng)建了一條鏈,并且把index+1,index就是前面說(shuō)到的getResponseWithInterceptorChain()傳入的初始值0
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);
.....
return response;
}
RealInterceptorChain.chain()這里面的邏輯是:
- 創(chuàng)建一條新鏈(下一個(gè)鏈),然后把創(chuàng)建
RealInterceptorChain對(duì)象時(shí)傳入的index+1,在getResponseWithInterceptorChain()中創(chuàng)建第一個(gè)攔截器鏈對(duì)象RealInterceptorChain時(shí)index傳入的是0;- 根據(jù)原始索引值拿到攔截器列表對(duì)應(yīng)位置的置攔截器
- 通過(guò)層層遞歸調(diào)用攔截器的
intercept()方法,拿到resoponse響應(yīng),并返回
這里的邏輯有點(diǎn)繞,先看下面這張圖:

根據(jù)上面的圖,屢屢邏輯:
- 當(dāng)調(diào)用
Response response = getResponseWithInterceptorChain()這行代碼的時(shí)候,從前面的源碼我們知道,RealCall.getResponseWithInterceptorChain() 會(huì)去創(chuàng)建第一個(gè)攔截器鏈RealInterceptorChain(也就是鏈1),index傳入的是0- 然后鏈1會(huì)去調(diào)用自己的
proceed(),在proceed()里面又重新去創(chuàng)建了一條新鏈RealInterceptorChain(也就是鏈2),鏈2的index是鏈1的index+1(也就是1)- 接著鏈1從攔截器列表中取出下標(biāo)為自己的index(下標(biāo)為0)的攔截器0,調(diào)用攔截器0的
intercept(),并且把鏈2作為intercept()的參數(shù)傳入- 通過(guò)查看okhttp內(nèi)置的5個(gè)攔截器的
intercept()可以看到,每個(gè)攔截器的intercept()內(nèi)部都會(huì)去調(diào)用chain.proceed(request),除了最后一個(gè),而這個(gè)chain就是調(diào)用intercept()傳入的參數(shù),也就是當(dāng)前鏈的下一個(gè)鏈(在第三步,攔截器0的intercept()傳入的參數(shù)是鏈2). 鏈2也是RealInterceptorChain類型,所以又重新走一遍第二步的邏輯,創(chuàng)鍵鏈3,然后取出攔截器1.......以此類推,直到index大于或等于interceptors.size()的時(shí)候結(jié)束遞歸- 當(dāng)執(zhí)行到最后一個(gè)攔截器4的時(shí)候,也就是okhttp的內(nèi)置攔截器CallServerInterceptor,CallServerInterceptor的
intercept()并沒(méi)有調(diào)用chain.proceed(request),因?yàn)槿绻舱{(diào)用,那么執(zhí)行if (index >= interceptors.size()) throw new AssertionError();這一行的時(shí)候,會(huì)拋異常,然后response會(huì)為null,所以在CallServerInterceptor.intercpt()里面就要從服務(wù)端讀取響應(yīng)數(shù)據(jù)- 當(dāng)攔截器4 CallServerInterceptor返回response,攔截器4的調(diào)用者鏈5的
proceed()也返回response。鏈5的調(diào)用者攔截器3也就返回reponse.......以此類推,最后直到鏈1的攔截器0返回response,鏈1的proceed()返回response,也就是RealCall.getResponseWithInterceptorChain()返回response
從上面的執(zhí)行邏輯可以看到,okhttp的攔截器鏈不僅僅是請(qǐng)求的時(shí)候環(huán)環(huán)相扣,拿到響應(yīng)返回的時(shí)候也是,所以我們才可以自定義攔截器,在請(qǐng)求和響應(yīng)的時(shí)候添加一些我們自己定義的操作。