Apache Async Http Client通过IP连接时自定义SNI服务器名配置问题
为Apache Async Http Client 4.1.3通过IP连接时配置SNI信息
当你需要通过IP地址连接HTTPS服务,同时指定SNI(Server Name Indication)信息确保SSL握手获取正确证书时,可以通过自定义SSLIOSessionStrategy实现,以下是具体步骤:
核心思路
Apache Async Http Client默认会在使用域名连接时自动处理SNI,但直接用IP连接时不会主动设置。我们需要重写SSLIOSessionStrategy的createSSLEngine方法,手动为SSLEngine添加SNI主机名参数,模拟openssl s_client -connect 1.2.3.4:443 -servername ab.cd.com的行为。
实现代码
1. 自定义SNI SSL会话策略
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLEngine; import javax.net.ssl.SNIHostName; import java.util.Collections; public class CustomSNISSLIOSessionStrategy extends SSLIOSessionStrategy { private final String sniServerName; public CustomSNISSLIOSessionStrategy(SSLContext sslContext, String sniServerName) { super(sslContext); this.sniServerName = sniServerName; } @Override public SSLEngine createSSLEngine(String host, int port) { SSLEngine sslEngine = super.createSSLEngine(host, port); SSLParameters sslParams = sslEngine.getSSLParameters(); // 设置SNI主机名,对应openssl的-servername参数 sslParams.setServerNames(Collections.singletonList(new SNIHostName(sniServerName))); sslEngine.setSSLParameters(sslParams); return sslEngine; } }
2. 构建带SNI配置的异步HTTP客户端
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import org.apache.http.impl.nio.client.HttpAsyncClients; import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager; import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; import org.apache.http.nio.reactor.IOReactorException; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContexts; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; public class AsyncHttpClientSNIDemo { public static CloseableHttpAsyncClient createSNIEnabledClient(String sniServerName) throws IOReactorException, NoSuchAlgorithmException, KeyManagementException { // 创建默认SSLContext,如需自定义证书信任可替换为自己配置的SSLContext SSLContext sslContext = SSLContexts.createDefault(); // 初始化自定义SNI策略 CustomSNISSLIOSessionStrategy sslStrategy = new CustomSNISSLIOSessionStrategy(sslContext, sniServerName); // 配置连接管理器,传入自定义SSL策略 PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager( new DefaultConnectingIOReactor(), null, sslStrategy, null); // 构建并返回异步客户端 return HttpAsyncClients.custom() .setConnectionManager(connManager) .build(); } public static void main(String[] args) throws Exception { // 替换为目标服务的SNI域名 String targetSNIName = "ab.cd.com"; CloseableHttpAsyncClient client = createSNIEnabledClient(targetSNIName); client.start(); // 发起请求时直接使用IP地址,示例:HttpGet request = new HttpGet("https://1.2.3.4:443/api"); // ... 执行请求逻辑 ... client.close(); } }
关键说明
- 自定义策略通过
SSLParameters.setServerNames方法添加SNI主机名,确保SSL握手时携带该信息,服务器据此返回对应域名的证书。 - 连接管理器初始化时传入自定义SSL策略,所有通过该管理器创建的连接都会自动应用SNI配置。
- 发起请求时直接使用IP地址作为目标URL即可,无需修改请求地址中的主机名。
内容的提问来源于stack exchange,提问作者abs060
相关产品推荐
相关产品推荐

