天天看點

OkHttp 3.7源碼分析(二)——攔截器&一個實際網絡請求的實作

okhttp3.7源碼分析文章清單如下:

<a href="https://yq.aliyun.com/articles/78105?spm=5176.8091938.0.0.hleond">okhttp源碼分析——整體架構</a>

<a href="https://yq.aliyun.com/articles/78104?spm=5176.8091938.0.0.hleond">okhttp源碼分析——攔截器</a>

<a href="https://yq.aliyun.com/articles/78103?spm=5176.8091938.0.0.hleond">okhttp源碼分析——任務隊列</a>

<a href="https://yq.aliyun.com/articles/78102?spm=5176.8091938.0.0.hleond">okhttp源碼分析——緩存政策</a>

<a href="https://yq.aliyun.com/articles/78101?spm=5176.8091938.0.0.hleond">okhttp源碼分析——多路複用</a>

前一篇部落格中我們介紹了okhttp的總體架構,接下來我們以一個具體的網絡請求來講述okhttp進行網絡通路的具體過程。由于該部分與okhttp的攔截器概念緊密聯系在一起,是以将這兩部分放在一起進行講解。

首先構造一個簡單的異步網絡通路demo:

<code>okhttpclient.newcall</code>實際是建立一個<code>realcall</code>執行個體:

<code>realcall.enqueue</code>實際就是講一個<code>realcall</code>放入到任務隊列中,等待合适的機會執行:

從代碼中可以看到最終<code>realcall</code>被轉化成一個<code>asynccall</code>并被放入到任務隊列中,任務隊列中的分發邏輯這裡先不說,相關實作會放在[okhttp源碼分析——任務隊列]()疑問進行介紹。這裡隻需要知道asynccall的excute方法最終将會被執行:

<code>execute</code>方法的邏輯并不複雜,簡單的說就是:

調用<code>getresponsewithinterceptorchain</code>擷取伺服器傳回

通知任務分發器(<code>client.dispatcher</code>)該任務已結束

<code>getresponsewithinterceptorchain</code>建構了一個攔截器鍊,通過依次執行該攔截器鍊中的每一個攔截器最終得到伺服器傳回。

首先來看下<code>getresponsewithinterceptorchain</code>的實作:

其邏輯大緻分為兩部分:

建立一系列攔截器,并将其放入一個攔截器數組中。這部分攔截器即包括使用者自定義的攔截器也包括架構内部攔截器

建立一個攔截器鍊<code>realinterceptorchain</code>,并執行攔截器鍊的<code>proceed</code>方法

接下來看下<code>realinterceptorchain</code>的實作邏輯:

在<code>proceed</code>方法中的核心代碼可以看到,proceed實際上也做了兩件事:

建立下一個攔截鍊。傳入<code>index + 1</code>使得下一個攔截器鍊隻能從下一個攔截器開始通路

執行索引為<code>index</code>的intercept方法,并将下一個攔截器鍊傳入該方法

接下來再看下第一個攔截器retryandfollowupinterceptor的intercept方法:

這段代碼最關鍵的代碼是:

這行代碼就是執行下一個攔截器鍊的proceed方法。而我們知道在下一個攔截器鍊中又會執行下一個攔截器的intercept方法。是以整個執行鍊就在攔截器與攔截器鍊中交替執行,最終完成所有攔截器的操作。這也是okhttp攔截器的鍊式執行邏輯。而一個攔截器的intercept方法所執行的邏輯大緻分為三部分:

在發起請求前對request進行處理

調用下一個攔截器,擷取response

對response進行處理,傳回給上一個攔截器

這就是okhttp攔截器機制的核心邏輯。是以一個網絡請求實際上就是一個個攔截器執行其intercept方法的過程。而這其中除了使用者自定義的攔截器外還有幾個核心攔截器完成了網絡通路的核心邏輯,按照先後順序依次是:

retryandfollowupinterceptor

bridgeinterceptor

cacheinterceptor

connectintercetot

callserverinterceptor

如上文代碼所示,retryandfollowupinterceptor負責兩部分邏輯:

在網絡請求失敗後進行重試

當伺服器傳回目前請求需要進行重定向時直接發起新的請求,并在條件允許情況下複用目前連接配接

bridgeinterceptor主要負責以下幾部分内容:

設定内容長度,内容編碼

設定gzip壓縮,并在接收到内容後進行解壓。省去了應用層處理資料解壓的麻煩

添加cookie

設定其他報頭,如<code>user-agent</code>,<code>host</code>,<code>keep-alive</code>等。其中<code>keep-alive</code>是實作多路複用的必要步驟

cacheinterceptor的職責很明确,就是負責cache的管理

當網絡請求有符合要求的cache時直接傳回cache

當伺服器傳回内容有改變時更新目前cache

如果目前cache失效,删除

connectinterceptor的intercept方法隻有一行關鍵代碼:

即為目前請求找到合适的連接配接,可能複用已有連接配接也可能是重新建立的連接配接,傳回的連接配接由連接配接池負責決定。

callserverinterceptor負責向伺服器發起真正的通路請求,并在接收到伺服器傳回後讀取響應傳回。

以上就是整個網絡通路的核心步驟,總結起來如下圖所示:

OkHttp 3.7源碼分析(二)——攔截器&amp;一個實際網絡請求的實作