Okhttp源碼學(xué)習(xí)二(攔截器的工作過(guò)程)

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);
  }
}

ChainInterceptor接口的內(nèi)部接口,RealInterceptorChain實(shí)現(xiàn)了 Interceptor.Chain接口,所以直接看RealInterceptorChainChain()方法:

 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()這里面的邏輯是:

  1. 創(chuàng)建一條新鏈(下一個(gè)鏈),然后把創(chuàng)建RealInterceptorChain對(duì)象時(shí)傳入的index+1,在 getResponseWithInterceptorChain()中創(chuàng)建第一個(gè)攔截器鏈對(duì)象RealInterceptorChain時(shí)index傳入的是0;
  2. 根據(jù)原始索引值拿到攔截器列表對(duì)應(yīng)位置的置攔截器
  3. 通過(guò)層層遞歸調(diào)用攔截器的intercept()方法,拿到resoponse響應(yīng),并返回

這里的邏輯有點(diǎn)繞,先看下面這張圖:


執(zhí)行邏輯.png

根據(jù)上面的圖,屢屢邏輯:

  1. 當(dāng)調(diào)用Response response = getResponseWithInterceptorChain()這行代碼的時(shí)候,從前面的源碼我們知道,RealCall.getResponseWithInterceptorChain() 會(huì)去創(chuàng)建第一個(gè)攔截器鏈RealInterceptorChain(也就是鏈1),index傳入的是0
  2. 然后鏈1會(huì)去調(diào)用自己的proceed(),在proceed()里面又重新去創(chuàng)建了一條新鏈RealInterceptorChain(也就是鏈2),鏈2的index是鏈1的index+1(也就是1)
  3. 接著鏈1從攔截器列表中取出下標(biāo)為自己的index(下標(biāo)為0)的攔截器0,調(diào)用攔截器0的intercept(),并且把鏈2作為intercept()的參數(shù)傳入
  4. 通過(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é)束遞歸
  5. 當(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ù)
  6. 當(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í)候添加一些我們自己定義的操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容