本文档介绍在 Java 应用中使用 OkHttp 接入 HTTPDNS 的方案。
1. 背景说明
如果您在 Java 端使用的网络框架是 OkHttp,通过调用 OkHttp 提供的自定义 DNS 服务接口,可以简洁优雅地使用 HTTPDNS 的服务。
OkHttp 是一个处理网络请求的开源项目,是 Java/Android 端最火热的轻量级框架,由移动支付 Square 公司贡献。随着 OkHttp 的不断成熟,越来越多的开发者使用 OkHttp 作为网络框架。
OkHttp 默认使用系统 DNS 服务 InetAddress 进行域名解析,同时也暴露了自定义 DNS 服务的接口,通过该接口我们可以优雅地使用 HTTPDNS。
2. 实现自定义 DNS 接口
OkHttp 暴露了 Dns 接口,通过实现该接口可以自定义 DNS 服务:
import com.alibaba.sdk.java.httpdns.HTTPDNSResult;
import com.alibaba.sdk.java.httpdns.HttpDnsClient;
import com.alibaba.sdk.java.httpdns.RequestIpType;
import okhttp3.Dns;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
public class OkHttpDns implements Dns {
private final HttpDnsClient httpDnsClient;
public OkHttpDns(HttpDnsClient httpDnsClient) {
this.httpDnsClient = httpDnsClient;
}
@Override
public List<InetAddress> lookup(String hostname) throws UnknownHostException {
HTTPDNSResult result = httpDnsClient.getHttpDnsResultForHostSyncNonBlocking(
hostname,
RequestIpType.both
);
List<InetAddress> inetAddresses = new ArrayList<>();
try {
if (result != null && result.getIps() != null) {
for (String ip : result.getIps()) {
inetAddresses.add(InetAddress.getByName(ip));
}
}
if (result != null && result.getIpv6s() != null) {
for (String ip : result.getIpv6s()) {
inetAddresses.add(InetAddress.getByName(ip));
}
}
} catch (UnknownHostException e) {
// 忽略单个 IP 解析失败
}
if (!inetAddresses.isEmpty()) {
return inetAddresses;
}
// 降级到系统 DNS
return Dns.SYSTEM.lookup(hostname);
}
}由于 OkHttp 内部有重试机制,重试时可能会选择不同的 IP 建立连接,所以在 lookup() 方法中返回包含多个 IP 的列表,可以有效避免单一 IP 不可用导致请求失败的情况。
3. 配置 OkHttpClient
创建 OkHttpClient 对象,传入自定义 DNS 服务:
HttpDnsClient httpDnsClient = HttpDnsClient.getClient(accountId);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.dns(new OkHttpDns(httpDnsClient))
.build();4. 总结
OkHttp + HTTPDNS 的主要优势:
实现简单:只需实现
Dns接口即可接入通用性强:在 HTTPS、SNI 以及设置 Cookie 等场景均适用,无需额外处理证书校验、域名检查等环节
自动重试:返回多个 IP 时,OkHttp 会自动尝试不同的 IP 建立连接
该文章对您有帮助吗?