HttpDNS功能说明及实现
功能說明
HTTPDNS使用HTTP協(xié)議進(jìn)行域名解析,代替現(xiàn)有基于UDP的DNS協(xié)議,域名解析請求直接發(fā)送到阿里云的HTTPDNS服務(wù)器,從而繞過運營商的Local DNS,能夠避免Local DNS造成的域名劫持問題和調(diào)度不精準(zhǔn)問題。
| 防劫持 | 繞過運營商Local DNS,避免域名劫持,讓每一次訪問都暢通無阻。 |
| 精準(zhǔn)調(diào)度 | 基于訪問的來源IP,獲得最精準(zhǔn)的解析結(jié)果,讓客戶端就近接入業(yè)務(wù)節(jié)點。 |
| 0ms解析延遲 | 通過熱點域名預(yù)解析、緩存DNS解析結(jié)果、解析結(jié)果懶更新策略等方式實現(xiàn)0解析延遲 |
| 快速生效 | 避免Local DNS不遵循權(quán)威TTL,解析結(jié)果長時間無法更新的問題 |
| 降低解析失敗率 | 有效降低無線場景下解析失敗的比率 |
防劫持
HTTPDNS代替了傳統(tǒng)的LocalDNS完成遞歸解析的功能,基于HTTP協(xié)議的設(shè)計可以適用于幾乎所有的網(wǎng)絡(luò)環(huán)境,同時保留了鑒權(quán)、HTTPS等更高安全性的擴展能力,避免惡意攻擊劫持行為。
精準(zhǔn)調(diào)度
傳統(tǒng)域名解析的調(diào)度精準(zhǔn)性問題,本質(zhì)根源在于Local DNS的部署和分配機制上。由于碎片化的管理方式,這些環(huán)節(jié)的服務(wù)質(zhì)量同樣很難得到保障。HTTPDNS在遞歸解析實現(xiàn)上優(yōu)化了與權(quán)威DNS的交互,通過<a name="https://datatracker.ietf.org/doc/rfc7871">edns-client-subnet</a>協(xié)議將終端用戶的IP信息直接交付給權(quán)威DNS,這樣權(quán)威DNS就可以忽略Local DNS IP信息,根據(jù)終端用戶的IP信息進(jìn)行精準(zhǔn)調(diào)度,避免Local DNS的坐標(biāo)干擾
DNS解析0延遲:
-
構(gòu)建客戶端DNS緩存;
通過合理的DNS緩存,我們確保每次網(wǎng)絡(luò)交互的DNS解析都是從內(nèi)存中獲取IP信息,從而大幅降低DNS解析開銷。根據(jù)業(yè)務(wù)的不同,我們可以制訂更豐富的緩存策略,如根據(jù)運營商緩存,可以在網(wǎng)絡(luò)切換的場景下復(fù)用已緩存的不同運營商線路的域名IP信息,避免網(wǎng)絡(luò)切換后進(jìn)行鏈路重選擇引入的DNS網(wǎng)絡(luò)解析開銷。另外,我們還可以引入IP本地化離線存儲,在客戶端重啟時快速從本地讀取域名IP信息,大幅提升首頁載入效率。 -
熱點域名預(yù)解析;
在客戶端啟動過程中,我們可以通過熱點域名的預(yù)解析完成熱點域名的緩存載入。當(dāng)真正的業(yè)務(wù)請求發(fā)生時,直接由內(nèi)存中讀取目標(biāo)域名的IP信息,避免傳統(tǒng)DNS的網(wǎng)絡(luò)開銷。 -
懶更新策略;
絕大多數(shù)場景下業(yè)務(wù)域名的IP信息變更并不頻繁,特別是在單次APP的使用周期內(nèi),域名解析獲取的IP往往是相同的(特殊業(yè)務(wù)場景除外)。因此我們可以利用DNS懶更新策略來實現(xiàn)TTL過期后的DNS快速解析。所謂DNS懶更新策略即客戶端不主動探測域名對應(yīng)IP的TTL時間,當(dāng)業(yè)務(wù)請求需要訪問某個業(yè)務(wù)域名時,查詢內(nèi)存緩存并返回該業(yè)務(wù)域名對應(yīng)的IP解析結(jié)果。如果IP解析結(jié)果的TTL已過期,則在后臺進(jìn)行異步DNS網(wǎng)絡(luò)解析與緩存結(jié)果更新。通過上述策略,用戶的所有DNS解析都在與內(nèi)存交互,避免了網(wǎng)絡(luò)交互引入的延遲。
實現(xiàn)方案
服務(wù)端:
服務(wù)端提供API接口,app端直接通過ip地址訪問,ip地址可以有多個
請求方式:HTTP GET
URL參數(shù)說明:
| host | 必須 | 要解析的域名 |
| ip | 可選 | 用戶的來源IP,如果沒指定這個參數(shù),默認(rèn)使用請求連接的源IP |
請求示例:
-
示例1(默認(rèn)來源IP):http://x.x.x.x/d?host=www.suning.com
-
示例2(指定來源IP):http://x.x.x.x/d?host=www.suning.com&ip=185.53.179.6
考慮到服務(wù)IP防攻擊之類的安全風(fēng)險,為保障服務(wù)可用性,HTTPDNS同時提供多個服務(wù)IP,當(dāng)某個服務(wù)IP在異常情況下不可用時,可以使用其它服務(wù)IP進(jìn)行重試。
請求成功時,HTTP響應(yīng)的狀態(tài)碼為200,響應(yīng)結(jié)果用JSON格式表示,示例如下:
{"host": "www.suning.com","ips": ["112.84.104.48"],"ttl": 57,"origin_ttl": 120 }請求失敗的響應(yīng)示例:
{"code": "MissingArgument" }錯誤碼列表如下:
| MissingArgument | 400 | 缺少必要參數(shù) |
| InvalidHost | 400 | 域名格式不合法 |
| MethodNotAllowed | 405 | 不支持的HTTP方法 |
| InternalError | 500 | 服務(wù)端內(nèi)部錯誤 |
錯誤處理
異常下的出錯兼容邏輯,主要包括異步請求,重試,降級
異步請求
訪問HTTPDNS服務(wù)時,應(yīng)該使用異步請求的策略,避免解析延遲太大而對業(yè)務(wù)造成影響,特別是在網(wǎng)絡(luò)環(huán)境異常或HTTPDNS服務(wù)IP異常不可 用時,如果用同步訪問,需要等待網(wǎng)絡(luò)超時后才會返回解析失敗,這個超時時間較大,可能對業(yè)務(wù)的使用體驗造成很大影響。異步請求策略:解析域名時,如果當(dāng)前緩存中有TTL未過期的IP,可直接使用;如果沒有,則立刻讓此次請求降級走原生LocalDNS解析,同 時另起線程異步地發(fā)起HTTPDNS請求進(jìn)行解析,更新緩存,這樣后續(xù)解析域名時就能命中緩存。重試
訪問HTTPDNS服務(wù)解析域名時,如果請求HTTPDNS服務(wù)端失敗,即HTTP請求沒有返回,可以進(jìn)行重試。大部分情況下,這種訪問失敗是由于網(wǎng)絡(luò)原因引起的,重試可以解決。降級
不管是因為什么原因,當(dāng)通過HTTPDNS服務(wù)無法獲得域名對應(yīng)的IP時,都必須降級:使用標(biāo)準(zhǔn)的DNS解析,通過Local DNS去解析域名。Android端:
OkHttp默認(rèn)使用系統(tǒng)DNS服務(wù)InetAddress進(jìn)行域名解析,但同時也暴露了自定義DNS服務(wù)的接口,通過該接口我們可以優(yōu)雅地使用HttpDns。
- 自定義DNS接口
OkHttp暴露了一個Dns接口,通過實現(xiàn)該接口,我們可以自定義Dns服務(wù):
public class OkHttpDns implements Dns {private static final Dns SYSTEM = Dns.SYSTEM;HttpDnsService httpdns;//httpdns 解析服務(wù)private static OkHttpDns instance = null;private OkHttpDns(Context context) {this.httpdns = HttpDns.getService(context, "account id");}public static OkHttpDns getInstance(Context context) {if(instance == null) {instance = new OkHttpDns(context);}return instance;}@Overridepublic List<InetAddress> lookup(String hostname) throws UnknownHostException {//通過異步解析接口獲取ipString ip = httpdns.getIpByHostAsync(hostname);if(ip != null) {//如果ip不為null,直接使用該ip進(jìn)行網(wǎng)絡(luò)請求List<InetAddress> inetAddresses = Arrays.asList(InetAddress.getAllByName(ip));Log.e("OkHttpDns", "inetAddresses:" + inetAddresses);return inetAddresses;}//如果返回null,走系統(tǒng)DNS服務(wù)解析域名return Dns.SYSTEM.lookup(hostname);} }- 創(chuàng)建OkHttpClient
創(chuàng)建OkHttpClient對象,傳入OkHttpDns對象代替默認(rèn)Dns服務(wù):
private void okhttpDnsRequest() {OkHttpClient client = new OkHttpClient.Builder().dns(OkHttpDns.getInstance(getApplicationContext())).build();Request request = new Request.Builder().url("http://www.aliyun.com").build();Response response = null;client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {e.printStackTrace();}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);DataInputStream dis = new DataInputStream(response.body().byteStream());int len;byte[] buff = new byte[4096];StringBuilder result = new StringBuilder();while ((len = dis.read(buff)) != -1) {result.append(new String(buff, 0, len));}Log.d("OkHttpDns", "Response: " + result.toString());}}); }- 總結(jié)
相比于通用方案,OkHttp+HttpDns有以下兩個主要優(yōu)勢:
實現(xiàn)簡單,只需通過實現(xiàn)Dns接口即可接入HttpDns服務(wù)通用性強,該方案在HTTPS,SNI以及設(shè)置Cookie等場景均適用。規(guī)避了證書校驗,域名檢查等環(huán)節(jié)IOS端:
基于NSURLProtocol可攔截iOS系統(tǒng)上基于上層網(wǎng)絡(luò)庫NSURLConnection/NSURLSession發(fā)出的網(wǎng)絡(luò)請求;
通過以下接口注冊自定義NSURLProtocol,用于攔截上層網(wǎng)絡(luò)請求,并創(chuàng)建新的網(wǎng)絡(luò)請求接管數(shù)據(jù)發(fā)送、接收、重定向等處理邏輯,將結(jié)果反饋給原始請求。
[NSURLProtocol registerClass:[CustomProtocol class]];自定義NSURLProtocol處理過程概述:
- 在canInitWithRequest中過濾要需要做HTTPDNS域名解析的請求;
- 請求攔截后,做HTTPDNS域名解析;
- 解析完成后,同普通請求一樣,替換URL.host字段,替換HTTP Header Host域,并接管該請求的數(shù)據(jù)發(fā)送、接收、重定向等處理;
作者:剛哥說
鏈接:https://www.jianshu.com/p/15ff2aeb5b5b
來源:簡書
簡書著作權(quán)歸作者所有,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處。
總結(jié)
以上是生活随笔為你收集整理的HttpDNS功能说明及实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Syslog系统日志配置
- 下一篇: HttpDns 原理是什么