日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

一、前言

談到優(yōu)化,首先第一步,肯定是把一個(gè)大功能,拆分成一個(gè)個(gè)細(xì)小的環(huán)節(jié),再單個(gè)拎出來找到可以優(yōu)化的點(diǎn),App 的網(wǎng)絡(luò)優(yōu)化也是如此。

在 App 訪問網(wǎng)絡(luò)的時(shí)候,DNS 解析是網(wǎng)絡(luò)請(qǐng)求的第一步,默認(rèn)我們使用運(yùn)營商的 LocalDNS 服務(wù)。有數(shù)據(jù)統(tǒng)計(jì),在這一塊 3G 網(wǎng)絡(luò)下,耗時(shí)在 200~300ms,4G 網(wǎng)絡(luò)下也需要 100ms。

解析慢,并不是 LocalDNS 最大的問題,它還存在一些更為嚴(yán)重的問題,例如:DNS 劫持、DNS 調(diào)度不準(zhǔn)確(緩存、轉(zhuǎn)發(fā)、NAT)導(dǎo)致性能退化等等,這些才是網(wǎng)絡(luò)優(yōu)化最應(yīng)該解決的問題。

想要優(yōu)化 DNS,現(xiàn)在最簡單成熟的方案,就是使用 HTTPDNS。

今天就來聊聊,DNS、HTTPDNS,以及在 Android 下,如何使用 OKHttp 來集成 HTTPDNS。

二、DNS 和 HTTPDNS

2.1 什么是 DNS

在說到 HTTPDNS 之前,先簡單了解一下什么是 DNS?

在網(wǎng)絡(luò)的世界中,每個(gè)有效的域名背后都有為其提供服務(wù)的服務(wù)器,而我們網(wǎng)絡(luò)通信的首要條件,就是知道服務(wù)器的 IP 地址。

但是記住域名(網(wǎng)址)肯定是比記住 IP 地址簡單。如果有某種方法,可以通過域名,查到其提供服務(wù)的服務(wù)器 IP 地址,那就非常方便了。這里就需要用到 DNS 服務(wù)器以及 DNS 解析。

DNS(Domain Name System),它的作用就是根據(jù)域名,查出對(duì)應(yīng)的 IP 地址,它是 HTTP 協(xié)議的前提。只有將域名正確的解析成 IP 地址后,后面的 HTTP 流程才可以繼續(xù)進(jìn)行下去。

DNS 服務(wù)器的要求,一定是高可用、高并發(fā)和分布式的服務(wù)器。它被分為多個(gè)層次結(jié)構(gòu)。

  • 根 DNS 服務(wù)器:返回頂級(jí)域 DNS 服務(wù)器的 IP 地址。
  • 頂級(jí)域 DNS 服務(wù)器:返回權(quán)威 DNS 服務(wù)器的 IP 地址。
  • 權(quán)威 DNS 服務(wù)器:返回相應(yīng)主機(jī)的 IP 地址。

這三類 DNS 服務(wù)器,類似一種樹狀的結(jié)構(gòu),分級(jí)存在。

百度技術(shù):“App 優(yōu)化網(wǎng)絡(luò),先從優(yōu)化 DNS 開始” | 原理到實(shí)戰(zhàn)

 

當(dāng)開始 DNS 解析的時(shí)候,如果 LocalDNS 沒有緩存,那就會(huì)向 LocalDNS 服務(wù)器請(qǐng)求(通常就是運(yùn)營商),如果還是沒有,就會(huì)一級(jí)一級(jí)的,從根域名查對(duì)應(yīng)的頂級(jí)域名,再從頂級(jí)域名查權(quán)威域名服務(wù)器,最后通過權(quán)威域名服務(wù)器,獲取具體域名對(duì)應(yīng)的 IP 地址。

百度技術(shù):“App 優(yōu)化網(wǎng)絡(luò),先從優(yōu)化 DNS 開始” | 原理到實(shí)戰(zhàn)

 

DNS 在提供域名和 IP 地址映射的過程中,其實(shí)提供了很多基于域名的功能,例如服務(wù)器的負(fù)載均衡,但是它也帶來了一些問題。

2.2 DNS 的問題

DNS 的細(xì)節(jié)還有很多,本文就不展開細(xì)說了,其問題總結(jié)來說就是幾點(diǎn)。

1. 不穩(wěn)定

DNS 劫持或者故障,導(dǎo)致服務(wù)不可用。

2. 不準(zhǔn)確

LocalDNS 調(diào)度,并不一定是就近原則,某些小運(yùn)營商沒有 DNS 服務(wù)器,直接調(diào)用其他運(yùn)營商的 DNS 服務(wù)器,最終直接跨網(wǎng)傳輸。例如:用戶側(cè)是移動(dòng)運(yùn)營商,調(diào)度到了電信的 IP,造成訪問慢,甚至訪問受限等問題。

3. 不及時(shí)

運(yùn)營商可能會(huì)修改 DNS 的 TTL(Time-To-Live,DNS 緩存時(shí)間),導(dǎo)致 DNS 的修改,延遲生效。

還有運(yùn)營商為了保證網(wǎng)內(nèi)用戶的訪問質(zhì)量,同時(shí)減少跨網(wǎng)結(jié)算,運(yùn)營商會(huì)在網(wǎng)內(nèi)搭建內(nèi)容緩存服務(wù)器,通過把域名強(qiáng)行指向內(nèi)容緩存服務(wù)器的地址,來實(shí)現(xiàn)本地本網(wǎng)流量完全留在本地的目的。

對(duì)此不同運(yùn)營商甚至實(shí)現(xiàn)都不一致,這對(duì)我們來說就是個(gè)黑匣子。

百度技術(shù):“App 優(yōu)化網(wǎng)絡(luò),先從優(yōu)化 DNS 開始” | 原理到實(shí)戰(zhàn)

 

正是因?yàn)?DNS 存在種種問題,所以牽出了 HTTPDNS。

2.3 HTTPDNS 的解決方案

DNS 不僅支持 UDP,它還支持 TCP,但是大部分標(biāo)準(zhǔn)的 DNS 都是基于 UDP 與 DNS 服務(wù)器的 53 端口進(jìn)行交互。

HTTPDNS 則不同,顧名思義它是利用 HTTP 協(xié)議與 NDS 服務(wù)器的 80 端口進(jìn)行交互。不走傳統(tǒng)的 DNS 解析,從而繞過運(yùn)營商的 LocalDNS 服務(wù)器,有效的防止了域名劫持,提高域名解析的效率。

百度技術(shù):“App 優(yōu)化網(wǎng)絡(luò),先從優(yōu)化 DNS 開始” | 原理到實(shí)戰(zhàn)

 

這就相當(dāng)于,每家各自基于 HTTP 協(xié)議,自己實(shí)現(xiàn)了一套域名解析,自己去維護(hù)了一份域名與 IP 的地址簿,而不是使用同一的地址簿(DNS服務(wù)器)。

各大云服務(wù)商,阿里云和騰訊云也提供了自己的 HTTPDNS 服務(wù),對(duì)于我們普通開發(fā)者,只需要付出少量的費(fèi)用,在手機(jī)端嵌入支持 HTTPDNS 的客戶端 SDK,即可使用。

三、 OKHttp 接入 HTTPDNS

既然了解了 HTTPDNS 的重要性,接下來看看如何在 OkHttp 中,集成 HTTPDNS。

OkHttp 是一個(gè)處理網(wǎng)絡(luò)請(qǐng)求的開源項(xiàng)目,是 Android 端最火熱的輕量級(jí)網(wǎng)絡(luò)框架。在 OkHttp 中,默認(rèn)是使用系統(tǒng)的 DNS 服務(wù) InetAddress 進(jìn)行域名解析。

InetAddress ip2= InetAddress.getByName("www.cxmydev.com");
System.out.println(ip2.getHostAddress());
System.out.println(ip2.getHostName());

而想在 OkHttp 中使用 HTTPDNS,有兩種方式。

  1. 通過攔截器,在發(fā)送請(qǐng)求之前,將域名替換為 IP 地址。
  2. 通過 OkHttp 提供的 .dns() 接口,配置 HTTPDNS。

對(duì)這兩種方法來說,當(dāng)然是推薦使用標(biāo)準(zhǔn) API 來實(shí)現(xiàn)了。攔截器的方式,也建議有所了解,實(shí)現(xiàn)很簡單,但是有坑。

3.1 攔截器接入方式

1. 攔截器接入

攔截器是 OkHttp 中,非常強(qiáng)大的一種機(jī)制,它可以在請(qǐng)求和響應(yīng)之間,做一些我們的定制操作。

在 OkHttp 中,可以通過實(shí)現(xiàn) Interceptor 接口,來定制一個(gè)攔截器。使用時(shí),只需要在 OkHttpClient.Builder 中,調(diào)用 addInterceptor() 方法來注冊(cè)此攔截器即可。

OkHttp 的攔截器不是本文的重點(diǎn),我們還是回到攔截器去實(shí)現(xiàn) HTTPDNS 的話題上,攔截器沒什么好說的,直接上相關(guān)代碼。

class HTTPDNSInterceptor : Interceptor{
 override fun intercept(chain: Interceptor.Chain): Response {
 val originRequest = chain.request()
 val httpUrl = originRequest.url()
 val url = httpUrl.toString()
 val host = httpUrl.host()
 val hostIP = HttpDNS.getIpByHost(host)
 val builder = originRequest.newBuilder()
 if(hostIP!=null){
 builder.url(HttpDNS.getIpUrl(url,host,hostIP))
 builder.header("host",hostIP)
 }
 val newRequest = builder.build()
 val newResponse = chain.proceed(newRequest)
 return newResponse
 }
}

在攔截器中,使用 HttpDNS 這個(gè)幫助類,通過 getIpByHost() 將 Host 轉(zhuǎn)為對(duì)應(yīng)的 IP。

如果通過抓包工具抓包,你會(huì)發(fā)現(xiàn),原本的類似 www.cxmydev.com/api/user 的請(qǐng)求,被替換為:220.181.57.xxx/api/user。

2. 攔截器接入的壞處

使用攔截器,直接繞過了 DNS 的步驟,在請(qǐng)求發(fā)送前,將 Host 替換為對(duì)應(yīng)的 IP 地址。

這種方案,在流程上很清晰,沒有任何技術(shù)性的問題。但是這種方案存在一些問題,例如:HTTPS 下 IP 直連的證書問題、代理的問題、Cookie 的問題等等。

其中最嚴(yán)重的問題是,此方案(攔截器+HTTPDNS)遇到 https 時(shí),如果存在一臺(tái)服務(wù)器支持多個(gè)域名,可能導(dǎo)致證書無法匹配的問題。

在說到這個(gè)問題之前,就要先了解一下 HTTPS 和 SNI。

HTTPS 是為了保證安全的,在發(fā)送 HTTPS 請(qǐng)求之前,首先要進(jìn)行 SSL/TLS 握手,握手的大致流程如下:

  1. 客戶端發(fā)起握手請(qǐng)求,攜帶隨機(jī)數(shù)、支持算法列表等參數(shù)。
  2. 服務(wù)端根據(jù)請(qǐng)求,選擇合適的算法,下發(fā)公鑰證書和隨機(jī)數(shù)。
  3. 客戶端對(duì)服務(wù)端證書,進(jìn)行校驗(yàn),并發(fā)送隨機(jī)數(shù)信息,該信息使用公鑰加密。
  4. 服務(wù)端通過私鑰獲取隨機(jī)數(shù)信息。
  5. 雙方根據(jù)以上交互的信息,生成 Session Ticket,用作該連接后續(xù)數(shù)據(jù)傳輸?shù)募用苊荑€。

在這個(gè)流程中,客戶端需要驗(yàn)證服務(wù)器下發(fā)的證書。首先通過本地保存的根證書解開證書鏈,確認(rèn)證書可信任,然后客戶端還需要檢查證書的 domain 域和擴(kuò)展域,看看是否包含本次請(qǐng)求的 HOST。

在這一步就出現(xiàn)了問題,當(dāng)使用攔截器時(shí),請(qǐng)求的 URL 中,HOST 會(huì)被替換成 HTTPDNS 解析出來的 IP。當(dāng)服務(wù)器存在多域名和證書的情況下,服務(wù)器在建立 SSL/TLS 握手時(shí),無法區(qū)分到底應(yīng)該返回那個(gè)證書,此時(shí)的策略可能返回默認(rèn)證書或者不返回,這就有可能導(dǎo)致客戶端在證書驗(yàn)證 domain 時(shí),出現(xiàn)不匹配的情況,最終導(dǎo)致 SSL/TLS 握手失敗。

這就引發(fā)出來 SNI 方案,SNI(Server Name Indication)是為了解決一個(gè)服務(wù)器使用多個(gè)域名和證書的 SSL/TLS 擴(kuò)展。

SNI 的工作原理,在連接到服務(wù)器建立 SSL 連接之前,先發(fā)送要訪問站點(diǎn)的域名(hostname),服務(wù)器根據(jù)這個(gè)域名返回正確的證書。現(xiàn)在,大部分操作系統(tǒng)和瀏覽器,都已經(jīng)很好的支持 SNI 擴(kuò)展。

3. 攔截器 + HTTPDNS 的解決方案

這個(gè)問題,其實(shí)也有解決方案,這里簡單介紹一下。

針對(duì) "domain 不匹配" 的問題,可以通過 hook 證書驗(yàn)證過程中的第二步,將 IP 直接替換成原來的域名,再執(zhí)行證書驗(yàn)證。

而 HttpURLConnect,提供了一個(gè) HostnameVerifier 接口,實(shí)現(xiàn)它即可完成替換。

public interface HostnameVerifier {
 public boolean verify(String hostname, SSLSession session);
}

如果使用 OkHttp,可以參考 OkHostnameVerifier (source://src/main/JAVA/okhttp3/internal/tls/OkHostnameVerifier.java) 的實(shí)現(xiàn),進(jìn)行替換。

本身 OkHttp 就不建議通過攔截器去做 HTTPDNS 的支持,所以這里就不展開討論了,這里只提出解決的思路,有興趣可以研究研究源碼。

3.2 OKHttp 標(biāo)準(zhǔn) API 接入

OkHttp 其實(shí)本身已經(jīng)暴露了一個(gè) Dns 接口,默認(rèn)的實(shí)現(xiàn)是使用系統(tǒng)的 InetAddress 類,發(fā)送 UDP 請(qǐng)求進(jìn)行 DNS 解析。

我們只需要實(shí)現(xiàn) OkHttp 的 Dns 接口,即可獲得 HTTPDNS 的支持。

在我們實(shí)現(xiàn)的 Dns 接口實(shí)現(xiàn)類中,解析 DNS 的方式,換成 HTTPDNS,將解析結(jié)果返回。

class HttpDns : Dns {
 override fun lookup(hostname: String): List<InetAddress> {
 val ip = HttpDnsHelper.getIpByHost(hostname)
 if (TextUtils.isEmpty(ip)) {
 //返回自己解析的地址列表
 return InetAddress.getAllByName(ip).toList() 
 } else {
 // 解析失敗,使用系統(tǒng)解析
 return Dns.SYSTEM.lookup(hostname)
 }
 }
}

使用也非常的簡單,在 OkHttp.build() 時(shí),通過 dns() 方法配置。

mOkHttpClient = httpBuilder
 .dns(HttpDns())
 .build();

這樣做的好處在于:

  1. 還是用域名進(jìn)行訪問,只是底層 DNS 解析換成了 HTTPDNS,以確保解析的 IP 地址符合預(yù)期。
  2. HTTPS 下的問題也得到解決,證書依然使用域名進(jìn)行校驗(yàn)。

OkHttp 既然暴露出 dns 接口,我們就盡量使用它。

四、小結(jié)時(shí)刻

現(xiàn)在大家知道,在做 App 的網(wǎng)絡(luò)優(yōu)化的時(shí)候,第一步就是使用 HTTPDNS 優(yōu)化 DNS 的步驟。

所有的優(yōu)化當(dāng)然是以最終效果為目的,這里提兩條大廠公開的數(shù)據(jù),對(duì)騰訊的產(chǎn)品,在接入 HTTPDNS 后,用戶平均延遲下降超過 10%,訪問失敗率下降超過五分之一。而百度 App 的 Feed 業(yè)務(wù),Android 劫持率由 0.25% 降低到 0.05%。

此種優(yōu)化方案,非常依賴 HTTPDNS 服務(wù)器,所以建議使用 阿里云、騰訊云 這樣相對(duì)穩(wěn)定的云服務(wù)商。

分享到:
標(biāo)簽:優(yōu)化 網(wǎng)絡(luò)
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績?cè)u(píng)定