1. 程式人生 > 實用技巧 >okhttp與jdk版本不相容分析

okhttp與jdk版本不相容分析

1、背景

最近在部署應用的時候,程式碼幾乎沒有太大改動。結果報瞭如下錯誤【clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on JDK 9+】:

於是緊急回滾,但錯誤依舊存在。在參考了部落格後,發現可能原因是jdk環境發生了改變。於是迅速檢視jdk版本,發現雲平臺運維近期將jdk版本由1.8.0_232升級到了1.8.0_252。但當時也有一批微服務用到了相同版本的okhttp,卻沒有報相應的錯誤。在升級okhttp版本暫時規避了這個問題後,最近也抽時間對此進行了研究。

2、排查呼叫過程

1. 程式碼中okhttp的trustHttps欄位設定是true,代表信任所有的https連線。具體實現時:

2. OkHttpClient.class中關於sslSocketFactory方法如下:

3. Platform.class中關於findPlatform方法如下:

4.Jdk9Platform是Platform的子類。Jdk9Platform.class中buildIfSupported方法如下:

可以看出來,3.x版本的okhttp中通過jdk中SSLParameters.class中包含setApplicationProtocols方法、SSLSocket.class中包含getApplicationProtocol來確定是jdk1.9以上版本。但在jdk 1.8.0_251之後的版本中都包含這兩個方法。4.3.0版本以下的okhttp都會對這個誤判。返回Jdk9Platform物件,步驟3直接返回jdk9物件。而在步驟2呼叫其trustManager方法時,由於父類和子類都包含trustManager方法,返回物件是子類,故會呼叫子類的實現(多型)。子類實現如下:

因此丟擲不支援的異常。

5. 在jdk1.8.0_251之前的版本中在步驟3 會直接通過new Platform()建立父類物件,之後就會呼叫父類中的trustManager方法:

這樣就不會報錯了。

3、 okhttp 4.3.0的改進

Okhttp 4.X版本採用kotlin語言進行了編寫,整體思路和Java版本區別不大。我們首先來看看okhttp是如何改進這個bug的:

我們在來看看新版本是如何判斷jdk9版本的:

採用了從系統讀取Java的主版本號,判斷是否大於9來實現的。

4、 過載方法

我們看到2.2節中sslSocketFactory方法標記了@deprecated註解,過載的方法為:

過載方法將信任管理設為了輸入引數。而且給出了使用建議:

其實就是呼叫sslSocketFactory時候傳入trustManager。(推薦此做法,無論okhttp、okhttp版本是什麼,都不會報錯)。

5、總結

針對jdk 1.8.0_251、okhttp4.3.0以下版本不相容問題,報如下錯誤【clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on JDK 9+】

解決辦法1:升級okhttp4.3.0以上版本或降級至jdk1.8.0_251之前版本。

解決辦法2:呼叫sslSocketFactory時候傳入trustManager。(推薦此做法,無論okhttp、okhttp版本是什麼,都不會報錯)。