在發送 HTTP 請求時,JDK 內建的 java.net.InetAddress 使用系統預設 DNS 解析器。某些測試或特殊環境(如指定測試機 IP、繞過 DNS 快取)需要自訂解析邏輯。本文說明 java.net.spi.InetAddressResolver(JDK 18+)或第三方庫(如 OkHttp 的 Dns 介面)如何切換解析策略。
// JDK 內部自動使用系統 hosts、DNS 伺服器設定
// 開發者無需額外代碼,InetAddress.getByName("example.com") 即可
/etc/hosts (Linux/macOS) 或 C:\Windows\System32\drivers\etc\hosts (Windows)。networkaddress.cache.ttl 控制 TTL)。OkHttp 提供 Dns 介面,可注入自訂解析邏輯:
import okhttp3.Dns;
import okhttp3.OkHttpClient;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
public class CustomDns implements Dns {
@Override
public List lookup(String hostname) throws UnknownHostException {
if ("dev4.baike.xx.com".equals(hostname)) {
return List.of(InetAddress.getByName("1.1.1.1"));
}
if ("baike.baidu.com".equals(hostname)) {
return List.of(InetAddress.getByName("2.2.2.2"));
}
// 其餘域名回退至系統預設
return Dns.SYSTEM.lookup(hostname);
}
}
// 使用
OkHttpClient client = new OkHttpClient.Builder()
.dns(new CustomDns())
.build();
| 場景 | 解決方案 |
|---|---|
| 本地開發對應測試環境 IP | 自訂 Dns 將特定域名解析至測試機 IP |
| 繞過 DNS 污染/劫持 | 指定可信 DNS 伺服器 IP(如 8.8.8.8) |
| 單元測試模擬網路 | Mock Dns 回傳固定 IP,不依賴真實網路 |
| 灰度發布/流量切分 | 依權重解析到不同版本服務 IP |
JDK 18 引入 java.net.spi.InetAddressResolverProvider,可透過 SPI 機制替換全域解析器,無需第三方庫:
// META-INF/services/java.net.spi.InetAddressResolverProvider
com.example.MyResolverProvider
// MyResolverProvider 實作 get() 回傳自訂 InetAddressResolver
sun.net.inetaddr.ttl)可能導致自訂解析器不生效,需設定 -Dsun.net.inetaddr.ttl=0 關閉快取。okhttp3.Dns 或 android.net.ConnectivityManager 相關 API。