天天看點

HttpClient/HttpURLConnection + HttpDns最佳實踐

如果您使用<code>httpclient</code>或<code>httpurlconnection</code>發起網絡請求,盡管無法直接自定義dns服務,但是由于<code>httpclient</code>和<code>httpurlconnection</code>也通過<code>inetaddress</code>進行域名解析,通過修改<code>inetaddress</code>的dns緩存,同樣可以比通用方案更為優雅地使用httpdns。

核心代碼位于<code>java.net.inetaddress.lookuphostbyname(string host, int netid)</code>

其中<code>addresscache</code>為<code>inetaddress</code>的本地緩存:

結合<code>inetaddress</code>的解析政策,我們可以通過如下方法實作自定義dns服務:

通過httpdns sdk擷取目标域名的ip

利用反射的方式擷取到<code>inetaddress.addresscache</code>對象

利用反射方式調用<code>addresscache.put()</code>方法,域名和ip的對應關系寫入<code>inetaddress</code>緩存

具體實作可參考以下代碼:

和通用方案相比,使用該方法具有下列優勢:

實作簡單

通用性強,該方案在https,sni以及設定cookie等場景均适用。規避了證書校驗,域名檢查等環節

全局生效,<code>inetaddress.addresscache</code>為全局單例,該方案對所有使用<code>inetaddress</code>作為域名解析服務的請求全部生效

另外使用該方案請務必注意以下幾點:

<code>addresscache</code>的預設ttl為2s,且預設最多可以儲存16條緩存記錄:

android虛拟機下反射規則與jvm存在差異,無法直接修改final變量的值。是以使用該方法請務必注意ip過期時間及緩存數量。另外針對該問題可嘗試另一種解決方案:重寫addresscache類,并通過classloader優先加載,覆寫系統類。

<code>addresscache.put</code>方法在 api 21進行了改動,增加了<code>netid</code>參數,為保證相容性需要針對不同版本差別處理。具體方案參考上文代碼

該方式可以解決https,sni以及設定cookie等場景,但不适用于webview場景。android webview使用<code>chromium</code>或<code>webkit</code>作為核心(android 4.4開始,webview核心由chromium替代webkit)。上述兩者均繞開inetaddress而直接使用系統dns服務,是以該方案對此場景無效。

繼續閱讀