HttpDNS功能說明及實現(xiàn)

功能說明

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等更高安全性的擴(kuò)展能力,避免惡意攻擊劫持行為。

精準(zhǔn)調(diào)度

傳統(tǒng)域名解析的調(diào)度精準(zhǔn)性問題,本質(zhì)根源在于Local DNS的部署和分配機(jī)制上。由于碎片化的管理方式,這些環(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

請求示例:

考慮到服務(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"
}

錯誤碼列表如下:

錯誤碼 HTTP狀態(tài)碼 描述
MissingArgument 400 缺少必要參數(shù)
InvalidHost 400 域名格式不合法
MethodNotAllowed 405 不支持的HTTP方法
InternalError 500 服務(wù)端內(nèi)部錯誤
錯誤處理

異常下的出錯兼容邏輯,主要包括異步請求,重試,降級

異步請求

訪問HTTPDNS服務(wù)時,應(yīng)該使用異步請求的策略,避免解析延遲太大而對業(yè)務(wù)造成影響,特別是在網(wǎng)絡(luò)環(huán)境異?;騂TTPDNS服務(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;
    }
    @Override
    public List<InetAddress> lookup(String hostname) throws UnknownHostException {
        //通過異步解析接口獲取ip
        String 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() {
        @Override
        public void onFailure(Call call, IOException e) {
            e.printStackTrace();
        }
        @Override
        public 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ā)送、接收、重定向等處理;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容