okhttp攔截器-責(zé)任鏈模式

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
最后編輯于
?著作權(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ù)。

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