1. 程式人生 > >OkHttp五大攔截器(自己專業整理)

OkHttp五大攔截器(自己專業整理)

一、什麼是OkHttp3

(1)定義:

OkHttp3是一個處理網路請求的開源專案,是目前最火的網路框架,作者是Square公司,
用於代替Android提供的HttpConnection和HttpClient。**

(2)OkHttp的特點

       1、是基於建造者模式(將一個複雜物件的構建與它的表示分離,用於屬性引數很多          時。)建立的
建造者模式:https://www.jianshu.com/p/be290ccea05a
      
      2、鏈式呼叫,每一個方法的返回值型別都是當前類的物件
      
(3)它的優點是什麼

         支援HTTP2/SPDY(SPDY是Google開發的基於TCP的傳輸層協議,用以最小化網路延遲,提升網路速度,優化使用者的網路使用體驗。)

         socket自動選擇最好路線,並支援自動重連,擁有自動維護的socket連線池,減少握手次數,減少了請求延遲,
共享Socket,減少對伺服器的請求次數。


擁有Interceptors輕鬆處理請求與響應(自動處理GZip壓縮)。

二、OKHttp的功能

PUT,DELETE,POST,GET等請求

檔案的上傳下載

載入圖片(內部會圖片大小自動壓縮)

支援請求回撥,直接返回物件、物件集合

支援session的保持

OkHttp請求流程

使用 OkHttp 發起一個請求主要三步:

1、需要構造一個 OkHttpClient

2、構造請求資訊 Request

3、發起請求

OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder().url("http://www.baidu.com")
                        .build();
                try {
                    Response response = client.newCall(request).execute();
                    if (response.isSuccessful()) {
                        System.out.println("成功");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }


發起一個請求整體流程:
首先當OkHttpClient物件想要傳送一個網路請求的時會執行newCall()方法這是我們將Request放在這個方法裡邊,
之後通過返回的okhttp的物件去去呼叫newCall方法
我們是從newCall開始的在原始碼中newCall會給我們返回個RealCall,newRealCall();
在RealCall中會將我們傳進來的request傳給我們的OrigginalRequest物件
(OrigginalRequest之後會在getresponseIntecepterchain裡的攔截鏈RealInterceptorChain()呼叫)

接下來如果我們是去進行一個同步請求的話也就是在程式碼當中呼叫excute()方法
進入excute()方法之後首先會先呼叫client。dispatcher()。excute(this);
這個方法的目的是通知調節器dispatcher我現在要開始執行任務瞭然後呼叫了getresponseInterceptorchain()方法
在這個方法執行結束以後會給我們返回一個通過http請求獲取的request物件
最後會呼叫client。dispatcher。finish()來通知排程器dispatcher我現在任務執行結束了你可以讓其他的認為來執行了
然後我們來說說它具體的執行過程,具體的執行過程是·在getresponseInterceptorchain()中執行的
**在這個方法裡有一個泛型是interceptor也就是攔截器的集合在這個結合裡存入了5個攔截器
之後建立了一個攔截鏈RealInt**erceptorChain();通過我們攔截鏈獲取的物件去呼叫process()方法
這個也就是我們所說的鏈式呼叫
在這個方法中有一個索引值index每次我們去呼叫這個process方法的時候他都會加1**
然**後我們會根據這個索引值去判斷我們去呼叫哪個攔截器當我們第一次呼叫這個方法的時候index為1回去呼叫我們集合當中
的第一個攔截器當攔截器執行完畢之後會去建立一個新的攔截鏈並且通過這個新的攔截鏈去再次呼叫process方法
然後去執行下一個攔截器
一直到所有的攔截器都呼叫完畢它會給我們返回一個的Request物件
而這個過程就是一個遞迴;
那麼它是如何去判斷我們已經呼叫到最後一個攔截器了那?
它是通過索引值index當index>集合的長度的時候那麼它就會結束這個方法了因為我們index是從1開始的
所以需要index值大於集合長度的時候
我們集合裡的攔截器才會全部執行完畢
然後我們去說一說這5個攔截器都是什麼分別有什麼作用

                                            (五大攔截器)
一、RetryAndFollowUpInterceptor (重定向攔截器)

       RetryAndFollowUpInterceptor 的攔截操作中做了這麼幾件事:

      1、建立一個 StreamAllocation

      2、發起請求

      3、請求異常時會重試

      4、根據響應碼做重定向和重試

      5、重定向時如果地址不一致會釋放連線

      6、另外也儲存是否取消的狀態值,在重試、請求得到響應後都會判斷是否取消

二、BridgeInterceptor (橋接攔截器)

       內建的攔截器中第二個是 BridgeInterceptor。Bridge,橋,什麼橋?連線使用者請求資訊 和 HTTP 請求的橋樑。

       BridgeInterceptor 負責把使用者構造的請求轉換為傳送到伺服器的請求、把伺服器返回的響應轉換為使用者友好的響應。

      我們說下僑界攔截器大概都做了什麼吧,請求前:

             1、如果這個請求有請求體,就新增 Content-Type, Content-Length 等

             2、如果這個請求沒有 Host,就通過 url 來獲取 Host 值新增到 Header 中

             3、如果這個請求沒有接收的資料型別Accept-Encoding,且沒指定接收的資料範圍,就新增預設接受格式為 gzip

            5、去 CookieJar 中根據 url 查詢 Cookie 新增到 Header

            6、如果當前沒有,就新增 User-Agent 資訊

發起請求後:

           7、解析響應 Header 中的 Cookie

           8、如果想要資料的格式是 gzip,就建立 GzipSource 進行解壓,同時移除 Content-Encoding 和 Content-Length

三、CacheInterceptor (快取攔截器)

        第三個攔截器是快取處理攔截器 CacheInterceptor,它的重要性用一句話來描述:最快的請求就是不請求,直接用快取。
       首先,根據request來判斷cache中是否有快取的response,如果有,得到這個response,然後進行判斷當前response是否有效,
沒有將cacheCandate賦值為空。
根據request判斷快取的策略,是否要使用了網路,快取 或兩者都使用
呼叫下一個攔截器,決定從網路上來得到response
如果本地已經存在cacheResponse,那麼讓它和網路得到的networkResponse做比較,決定是否來更新快取的cacheResponse
快取未經快取過的response

四、ConnectInterceptor (連線攔截器)

        我們知道,TCP 協議需要需要建立連線才能進行通訊,每次請求都建立連線會極大地影響通訊效率。

       OkHttp 的優點之一優化了連線的建立:內部維護了可以重複使用的 Socket 連線池,減少握手次數,加快請求響應。

               1、連線 RealConnection 是對 Socket 的封裝

               2、OkHttp 的連線複用主要是通過 StreamAllocation 來實現的,每個連線上持有一個。

               3、StreamAllocation 引用的列表,以此來標識當前連線是否空閒

               4、判斷連線是否可以重用,除了比較連線當前的 host,也可以比較路由資訊

               5、連線池在新增新連線時會執行清理任務,預設最多空閒連線為 5,最長空閒時間為 5 分鐘

五、CallServerInterceptor(讀寫攔截器)

        最後一個攔截器,CallServerInterceptor,它負責實現網路 IO,所有攔截器都要依賴它才能拿到響應資料。

        1、CallServerInterceptor 首先會將請求中的 header 寫給伺服器

       2、如果有請求體的話,會再將 body 傳送給伺服器

       3、最後通過httpCodec.finishRequest() 結束 http 請求的傳送

      4、然後從連線中讀取伺服器的響應,並構造 Response

      5、如果請求的 header或伺服器響應的 header 中,Connection 的值為 close,就關閉連線

      6、最後返回 Response


然後說一說非同步請求:

        同步中我們呼叫完newCall方法之後會去呼叫excute()方法;
而非同步中我們回去呼叫enqueue()方法;
並且呼叫這個非同步方法會實現Call介面,在原始碼裡邊,RealCall是Call介面的實現類
,也就是說獲取這個非同步任務的是ReallCall,ReallCall會把這個非同步任務交給他的內部類AcycCall  
AcyCall是NamedRunnable的實現類,NamedRunnable實現了Runnanle介面,通俗易懂省的說AcyCall是一個子執行緒,
在AcynCall這個類裡邊有一個enqueye()的方法  ,這時AcynCall 又將任務交給dispatcher去執行入隊操作,
而且這裡還有一個getResponsewithIntertorchan()這個方法是真正拿到響應並且通過介面回撥返回給OkHttpClient物件()

Dispatcher這個類是非同步任務排程器,在這個類裡邊有一個不限制執行緒數量的一個執行緒池,
也就是說 dispatcher線上程池裡邊開啟了一個子執行緒去執行這個非同步任務並進行處理,
處理完畢後他會把處理完的資料交給getResponsewithIntertorchan()    
而在getResponseWithInterceptorChain() 方法裡會通過鏈式呼叫拿到請求結果Resquest這個跟同步方法裡是一樣的