全部產品
Search
文件中心

HTTPDNS:Android端HTTPDNS+OkHttp最佳實務

更新時間:Jan 22, 2026

通過Android SDK接入流程這篇文檔,您已經瞭解了Android SDK匯入、配置、解析IP、應用到網路程式庫和接入驗證的完整流程,本文主要介紹OkHttp接入HTTPDNS的具體方案。

1. 背景說明

如果您在Android端使用的網路架構是OkHttp,通過調用OkHttp提供的自訂DNS服務介面,可以簡潔優雅地使用HTTPDNS的服務。

OkHttp是一個處理網路請求的開源專案,是Android端最火熱的輕量級架構,由移動支付Square公司貢獻用於替代HttpUrlConnection和Apache HttpClient。隨著OkHttp的不斷成熟,越來越多的Android開發人員使用OkHttp作為網路架構。

OkHttp預設使用系統DNS服務InetAddress進行網域名稱解析,同時也暴露了自訂DNS服務的介面,通過該介面我們可以優雅地使用HTTPDNS。

說明

本實踐對於Retrofit+OkHttp同樣適用,將配置好的OkHttpClient作為Retrofit.Builder::client(OkHttpClient)參數傳入即可。

2. 自訂DNS介面

OkHttp暴露了一個DNS介面,通過實現該介面,我們可以自訂DNS服務:

class OkHttpDns constructor(context: Context): Dns {
    private var mContext: Context

    init {
        mContext = context
    }
    @Throws(UnknownHostException::class)
    override fun lookup(host: String): List<InetAddress> {
        val httpdnsResult: HTTPDNSResult = HttpDns.getService(accountID)
            .getHttpDnsResultForHostSyncNonBlocking(host, RequestIpType.auto)
        val inetAddresses: MutableList<InetAddress> = ArrayList()
        var address: InetAddress
        try {
            if (httpdnsResult.ips != null) {
                //處理IPv4地址
                for (ipv4 in httpdnsResult.ips) {
                    address = InetAddress.getByName(ipv4)
                    inetAddresses.add(address)
                }
            }
            if (httpdnsResult.ipv6s != null) {
                //處理IPv6地址
                for (ipv6 in httpdnsResult.ipv6s) {
                    address = InetAddress.getByName(ipv6)
                    inetAddresses.add(address)
                }
            }
        } catch (e: UnknownHostException) {
        }
        return if (!inetAddresses.isEmpty()) {
            inetAddresses
        } else Dns.SYSTEM.lookup(host)
    }
}
public class OkHttpDns implements Dns {
    private Context mContext;
    public OkHttpDns(Context context) {
        mContext = context;
    }
    @Override
    public List<InetAddress> lookup(String host) throws UnknownHostException {
        HTTPDNSResult httpdnsResult = HttpDns.getService(accountID).getHttpDnsResultForHostSync(host, RequestIpType.both);
        List<InetAddress> inetAddresses = new ArrayList<>();
        InetAddress address;
        try {
            if (httpdnsResult.getIps() != null) {
                //處理IPv4地址
                for (String ipv4 : httpdnsResult.getIps()) {
                    address = InetAddress.getByName(ipv4);
                    inetAddresses.add(address);
                }
            }

            if (httpdnsResult.getIpv6s() != null) {
                //處理IPv6地址
                for (String ipv6 : httpdnsResult.getIpv6s()) {
                    address = InetAddress.getByName(ipv6);
                    inetAddresses.add(address);
                }
            }
        } catch (UnknownHostException e) {

        }

        if (!inetAddresses.isEmpty()) {
            return inetAddresses;
        }

        return okhttp3.Dns.SYSTEM.lookup(host);
    }
}

由於okhttp內部有重試機制,重試時可能會選擇不同的IP建立串連,所以在Dns介面的lookup()方法中,可以返回包含多個IP的List<InetAddress>,可以有效避免返回單一IP,而這個IP不可用導致該次請求完全失敗的情況。

3. 配置OkHttpClient

建立OkHttpClient對象,傳入OkHttpDns對象代替預設DNS服務:

private fun initOkHttp(context: Context) {
    val client = OkHttpClient.Builder() 
        //okhttp其他初始化配置請根據需求進行配置
        .dns(OkHttpDns(context))
        .build()
}
private void initOkHttp(Context context) {
    OkHttpClient client = new OkHttpClient.Builder()
    //okhttp其他初始化配置請根據需求進行配置
    .dns(new OkHttpDns(context))
    .build();
}

以上就是OkHttp+HttpDns實現的全部代碼。

4. 驗證

接入完成後,請參考驗證網路程式庫驗證成功文檔,通過劫持類比或錯誤注射測試等方式,驗證整合是否成功。

5. 總結

OkHttp+HttpDns有以下兩個主要優勢:

  • 實現簡單,只需通過實現DNS介面即可接入HttpDns服務。

  • 通用性強,該方案在HTTPS,SNI以及設定Cookie等情境均適用。規避了認證校正,網域名稱檢查等環節