Use HTTPDNS for DNS resolution in Apache HttpClient 4.x and 5.x by implementing a custom DnsResolver.
1. Background
Both Apache HttpClient 4.x and 5.x support HTTPDNS integration through the DnsResolver interface.
2. Implement a custom DnsResolver
HttpClient 5.x
import org.apache.hc.client5.http.DnsResolver;
import com.alibaba.sdk.java.httpdns.HttpDnsClient;
import com.alibaba.sdk.java.httpdns.HTTPDNSResult;
import com.alibaba.sdk.java.httpdns.RequestIpType;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
public class HttpDnsResolver implements DnsResolver {
private final HttpDnsClient httpDnsClient;
public HttpDnsResolver(HttpDnsClient httpDnsClient) {
this.httpDnsClient = httpDnsClient;
}
@Override
public String resolveCanonicalHostname(String host) {
return host;
}
@Override
public InetAddress[] resolve(String host) throws UnknownHostException {
HTTPDNSResult result = httpDnsClient.getHttpDnsResultForHostSyncNonBlocking(host, RequestIpType.both);
List<InetAddress> addresses = new ArrayList<>();
try {
if (result != null && result.getIps() != null) {
for (String ip : result.getIps()) {
addresses.add(InetAddress.getByName(ip));
}
}
if (result != null && result.getIpv6s() != null) {
for (String ip : result.getIpv6s()) {
addresses.add(InetAddress.getByName(ip));
}
}
} catch (UnknownHostException e) {
// Ignore the failure to parse a single IP address.
}
if (!addresses.isEmpty()) {
return addresses.toArray(new InetAddress[0]);
}
// Degrade to the system DNS.
return InetAddress.getAllByName(host);
}
}
HttpClient 4.x
import org.apache.http.conn.DnsResolver;
import com.alibaba.sdk.java.httpdns.HttpDnsClient;
import com.alibaba.sdk.java.httpdns.HTTPDNSResult;
import com.alibaba.sdk.java.httpdns.RequestIpType;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
public class HttpDnsResolver4 implements DnsResolver {
private final HttpDnsClient httpDnsClient;
public HttpDnsResolver4(HttpDnsClient httpDnsClient) {
this.httpDnsClient = httpDnsClient;
}
@Override
public InetAddress[] resolve(String host) throws UnknownHostException {
HTTPDNSResult result = httpDnsClient.getHttpDnsResultForHostSyncNonBlocking(host, RequestIpType.both);
List<InetAddress> addresses = new ArrayList<>();
try {
if (result != null && result.getIps() != null) {
for (String ip : result.getIps()) {
addresses.add(InetAddress.getByName(ip));
}
}
if (result != null && result.getIpv6s() != null) {
for (String ip : result.getIpv6s()) {
addresses.add(InetAddress.getByName(ip));
}
}
} catch (UnknownHostException e) {
// Ignore the failure to parse a single IP address.
}
if (!addresses.isEmpty()) {
return addresses.toArray(new InetAddress[0]);
}
// Degrade to the system DNS.
return InetAddress.getAllByName(host);
}
}
Note
The DnsResolver for versions 4.x and 5.x comes from different packages. For version 5.x, you must also implement the resolveCanonicalHostname() method.
3. Configure HttpClient
HttpClient 5.x
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
HttpDnsClient httpDnsClient = HttpDnsClient.getClient(accountId);
HttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
.setDnsResolver(new HttpDnsResolver(httpDnsClient))
.build();
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
HttpClient 4.x
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
HttpDnsClient httpDnsClient = HttpDnsClient.getClient(accountId);
CloseableHttpClient httpClient = HttpClients.custom()
.setDnsResolver(new HttpDnsResolver4(httpDnsClient))
.build();
4. Summary
Advantages of this approach:
-
Simple integration: Requires only a
DnsResolverimplementation. -
High versatility: Works with HTTPS, SNI, and cookies without additional certificate validation or domain verification.
-
Version compatibility: Supports both HttpClient 4.x and 5.x.