先來了解一下OkHttp的歷史,最先是square公司以爲Android給的HttpClient這塊的庫不太好用,因而乎作了一層包裝,再後來他們包裝的這個庫被Android官方給收回去了,而Android內部的HttpUrlConnection的實現用的實際上是OkHttp的代碼,而Okhttp是徹底從新寫的一套HTTP庫,包含TCP、TLS的實現,最初是依賴於Google的那套網絡框架,而如今徹底不依賴了,最終還被Google給收購了,因此,好好了解OkHttp的本質是毋庸置疑的。html
先上一下OkHttp的官網瞅下:git
看一下它的簡單用法:github
好,我們仍是以上一節【http://www.javashuo.com/article/p-azwuqyvf-bx.html】獲取github的倉庫爲例,簡單用一下OkHttp,以下:web
首先增長OkHttp的依賴:api
而後來訪問這個接口「https://api.github.com/users/webor2006/repos」爲例,看下OkHttp是如何來請求的:瀏覽器
運行一下:服務器
其實緣由是在build中木有指定Java的編譯版本爲Java8致使,由於OkHttp庫中現在用到了Lambda表達式,因此指定一下:網絡
再次運行:框架
ok,關於用法就到這,關於OkHttp的具體使用這裏就不詳細贅述啦,用一用就會了,重點是分析它的原理機制,直接開始看源碼了,首先先看下它:ide
其中Request又是採用Builder模式來構建的,真的是無處不見Builder模式:
點進去看一下源碼:
能夠發現是由RealCall來返回的,很明顯RealCall是Call的具體實現,因此點擊RealCall.newRealCall看下它的源碼:
其中爲啥第二個參數名叫originalRequest,也就是在以後會對這個Request進行轉型,因此這是一個最初始的狀態;第三個參數涉及到了WebSocket,那啥叫WebSocket呢,百度百科一下:
也就是說它實際上是HTTP的一種擴展,正常的HTTP服務器端是不可能主動給客戶端消息推送的,而WebSocket通常是炒股交易的軟件會用,由於消息會比較實時,一般軟件 是不會用到它的,瞭解一下既可。
接下來再繼續:
那這個eventListener有啥用呢?HTTP請求過程當中有各類狀態,如TCP鏈接、SSL鏈接、請求等狀態,它主要是用來記錄這些狀態用的,不重要,貌似這個方法比較簡單,接着來就須要分析一下它了:
走進去:
很明顯它的實現應該是在RealCall裏面以下:
分析核心代碼,首先調用eventListener中的一個狀態方法:
而後接下來一句就是核心代碼了:
這句代碼涉及到三個東東:dispatcher()、enqueue()、AsyncCall,因此分別來了解一下:
dispatcher():
那瞅一下Dispatcher類:
而它用到了線程池:
假如想要全部的請求一個個前後執行,那隻要將上面的max設置爲1既可。
enqueue():
接下來則看一下它的源碼:
這裏有三個隊列定義於Dispatcher類中,以下:
因此說Dispatcher類就是一個任務調度類。
AsyncCall:
enqueue方法參數中還涉及到此類,先來瞅一下:
貌似對於Runnable應該裏面會有一個run()方法吧,可AsyncCall中木有看到,如它的結構所示:
那有可能定義在它的父類NamedRunnable中,因此瞅一下:
final class AsyncCall extends NamedRunnable { private final Callback responseCallback; private volatile AtomicInteger callsPerHost = new AtomicInteger(0); AsyncCall(Callback responseCallback) { super("OkHttp %s", redactedUrl()); this.responseCallback = responseCallback; } ... @Override protected void execute() { boolean signalledCallback = false; timeout.enter(); try { Response response = getResponseWithInterceptorChain(); if (retryAndFollowUpInterceptor.isCanceled()) { signalledCallback = true; responseCallback.onFailure(RealCall.this, new IOException("Canceled")); } else { signalledCallback = true; responseCallback.onResponse(RealCall.this, response); } } catch (IOException e) { e = timeoutExit(e); if (signalledCallback) { // Do not signal the callback twice! Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e); } else { eventListener.callFailed(RealCall.this, e); responseCallback.onFailure(RealCall.this, e); } } finally { client.dispatcher().finished(this); } } }
那這裏面應該就是整個請求處理的關鍵,下面來搞定它:
不過這裏暫且不深刻分析它,先來總結一下enqueue()的整個流程:它會去調用Dispather.enqueue()方法,而這個方法會生成一個AsyncCall對象,最終會執行AsyncCall.execute()方法,而後最終再真正請求給出結果反饋。
另外對於OkHttp的經典使用除了enqueue()異常請求以外,還有一個execute()方法,它是同步的,也來大體瞅一下它的實現:
也就是enqueue()和execute()就是是不是同步的區別而已。
好,接下來則須要研究兩個東東了:
一是OkHttpClient在實用角度(理解OkHttp跟Http的關係)須要理解一下它的配置項;
二是上面提到的攔截鏈。
好,先來瞅一下OkHttpClient這個類:
這個就是客戶端告訴OkHttp支持HTTP的版本,就像瀏覽器能支持HTTP1.0、HTTP1.2,這個屬性就是幹這個用的。
因此這個是告訴OkHttp是否支持HTTP,仍是支持HTTPS,而HTTPS要怎麼支持,也就是對於HTTP的底層支持OkHttp所有都實現了,這就能夠看出跟Retrofit的一個區別了,好,繼續!
關於這倆在以後再詳說,跟攔截器鏈有關,往下繼續:
這個還記得麼,回顧一下:
也就是它是用來建立eventListener的東東,往下:
關於它的使用場景在以前HTTPS中已經學習過了,這裏簡單點擊瞅一下:
它是JDK中的接口,其中OkHttp的實現以下:
就不細看了,繼續往下看:
對於有自簽名的需求用它是很是合適的,這裏來簡單瞭解一下它的用法,文檔上有描述,以下:
我們來貼過來試一下:
其中增長了一個驗證的選項,這樣就不會使用本地根證書進行驗證了,就會使用我們本身的驗證方式了,以下:
此時確定會驗證失敗,運行以下:
03-15 23:01:48.172 24248-24267/com.okhttpstudy.study E/cexo: Failed!!!Certificate pinning failure! Peer certificate chain: sha256/uL6J3XldY7njtfGsRP7HZgYsrNPrDZXpG7kT7wfg1m0=: CN=www.baidu.cn,OU=service operation department,O=BeiJing Baidu Netcom Science Technology Co.\, Ltd,L=Beijing,C=CN sha256/5kJvNEMw0KjrCAu7eXY5HZdvyCS13BbA0VJG1RSP91w=: CN=DigiCert SHA2 Secure Server CA,O=DigiCert Inc,C=US sha256/r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=: CN=DigiCert Global Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US Pinned certificates for baidu.com: sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
其會在錯誤中會將此網站的全部簽名信息都會列出來,此時要想自簽名讓其經過驗證,則將錯誤提示的三個sha值添加到okhttpclient上,以下:
這個當有自簽名的需求時仍是比較好用滴。再繼續:
那具體是怎麼用它的呢?
簡單瞅下它:
至此整個OkHttpClient的字段都過了一遍,很明顯經過了解這些字段的含義能知道OkHttp底層作了好多事,清楚的能看到處處有http的身影。
接下來則須要研究Okhttp最核心的攔截器鏈啦,以下:
點進入瞅瞅它的實現:
其中首先是準備各類interceptor,以下:
接着將其生成一個InterceptorChain對像,以下:
用圖來表達一下攔截器鏈:
最後執行攔截器鏈的proceed(),此時實際上是這麼個過程:
爲啥要一個鏈呢?這裏能夠舉一個漢堡相關的例子用來理解:有人打電話進來訂了漢堡的餐,而後店老闆將漢堡作好了而且給負責分發的員工,接着送餐員到店取了漢堡騎着電動送到訂餐人的家裏,而後送餐員將漢堡給了訂餐的人,與此同時訂餐人將錢給了送餐員, 送餐員又拿着錢回到了店裏,並從中拿了1塊錢的提成,而後將剩下的錢所有交給了負責分發的店員,而後店員又將錢交給了店長,這就是一個鏈,店長是鏈的起點【作漢堡並分配給店員】和終點【從店員中拿到錢】。當一個事件比較複雜的時候採用鏈的方式會職責清晰,每個鏈則就是攔截器。
其中關於proceed()這裏仍是以上面舉的漢堡的店長爲例進一步闡述一下:其實對於店長的proceed()過程就是「作漢堡並分發給店員--->等待收錢---->收錢以後裝進本身的褲腰袋」,而結合圖的第一個節點表示店長的鏈,其過程實際上是這樣:
此時店長proceed()了,則會將連接給下一個接點,也就是分發的店員,以下:
接着通過漫長的等待,最終會從店員中收到錢,此時節點就會回到了以下位置:
用更加形象一點的圖來表示整個proceed()的過程,其實有點像遞歸:
從中能夠看到鏈上的每個結點都執行proceed()以後則就行成了一個一去一回的完整鏈的過程。
大概理解攔截鏈以後,接下來則細看一下具體的各個鏈,對於OkHttp的鏈,有兩個能夠自動配置的,以下:
這個先放一下,先來看一下其它具體的攔截器
RetryAndFollowUpInterceptor:
第一個是它:
重試及重定向攔截器,點進去,對於每個攔截器主要是看它的intercept()方法,因此:
其裏面作的事情基本上如咱們上面理論所說會有以下三件事件【OkHttp全部鏈的工做方式都遵循此原則,因此理解它很是之重要!】:
一、最初的準備(準備漢堡並交給店員)。
其中瞅一下StreamAllocation:
基本上這個攔截器前置工做比較簡單,重點是後置工做。
二、等待結果(等待收錢)。
接着執行proceed():
此時就會等待它以後的全部節點都處理完以後,此proceed()纔會返回結果。
三、處理結果(將錢裝自本身口袋)。
也就是proceed()以後的則是處理結果,具體來瞅下此攔截器的後置處理:
因此瞅一下recover方法:
若是符合重試條件,那麼直接再次循環:
其它的重試處理也相似:
最終:
BridgeInterceptor:
點進來瞅下,能很清楚的看到http的影子,以下:
好,仍是按以前的三步驟來分析:
一、最初的準備(準備漢堡並交給店員)。
基本全是加頭信息:
也就是OkHttp自身就已經支持gzip壓縮解壓縮,也就是開發者徹底透明,具體解的地方在:
這個是須要開發者本身定義的,由於CookieJar默認是空實現的,以下:
其大體用法能夠這樣寫:
二、等待結果(等待收錢)。
固然就是執行proceed()方法嘍:
三、處理結果(將錢裝自本身口袋)。
基本上作解工做,在proceed()以後:
CacheInterceptor:
比較簡單,就直接過了。
ConnectInterceptor【真正跟http或https進行交互了】:
點進去瞅下細節,主要是看流程,由於這個流程可以讓咱們清楚的發現跟TCP和SSL的創建過程:
好,目前TCP的鏈接已經看到了,那SSL的鏈接呢?得回到上一層,這:
因此此攔截器的做用就是用來創建TCP+SSL鏈接用的,而它木有後置工做:
CallServerInterceptor:
由於它是最後一個攔截器了,因此木有proceed()了,作完事情直接返回就ok了,它都是作的實質工做,下面也來分析其關鍵代碼:
咱們看http1的就成:
也就是經過TCP來往服務器創建通訊了,接着來處理response並返回:
最後就只剩自定義的攔截器木有看了,這個比較簡單,首先能夠配置一個本身的攔截器,以下:
對於我在公司的項目一般會用這個攔截器來打印一下日誌,或者傳一些公共頭信息之類的,總之比較好用。
那對於這兩個自定義的攔截器,有啥區別呢?
因此若是想直接http數據時則須要用networkInterceptors,通常用不到它,主要是用上面的自定義攔截器。
到此,整個完整的鏈都分析完了,能夠看到OkHttp是整個接管了整個Http的工做,從TCP鏈接的創建,TLS鏈接的創建,HTTP報文相關的處理,而Retrofit是利用Okhttp來實現的,只是API作了不少的容錯。