Apache HttpClient HTTPS请求偶现IP访问致证书不匹配,如何强制用DNS?
强制Spring WS(Apache HttpClient)客户端始终使用DNS名称发起HTTPS请求
问题背景
客户端基于Apache HttpClient的Spring WS发起请求时,无规律出现SSL证书匹配错误:
javax.net.ssl.SSLPeerUnverifiedException: Certificate for <g.i.t.n.c.com> doesn't match any of the subject alternative names: [*.t.n.c.com]
原因是客户端偶尔跳过DNS名称直接用IP访问Ingress,导致获取到针对IP的错误证书;正常请求则携带SNI主机名信息,获取匹配g.i.t.n.c.com的正确证书。
解决方案
1. 禁用HttpClient路由缓存
Apache HttpClient默认缓存已解析的路由信息,可能导致后续请求复用IP而非重新解析DNS。通过自定义路由规划器强制每次请求重新解析:
CloseableHttpClient httpClient = HttpClientBuilder.create() .setRoutePlanner(new DefaultRoutePlanner(DefaultSchemePortResolver.INSTANCE) { @Override public HttpRoute determineRoute(HttpHost target, HttpRequest request, HttpContext context) throws HttpException { // 清空路由缓存,强制每次重新解析DNS context.removeAttribute(HttpClientContext.ROUTE_INFO); return super.determineRoute(target, request, context); } }) .build(); // 注入到Spring WS的WebServiceTemplate WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender(httpClient); webServiceTemplate.setMessageSender(messageSender);
2. 强制SSL连接携带SNI并验证主机名
确保SSL连接工厂始终携带SNI扩展,严格基于DNS名称验证证书:
SSLContext sslContext = SSLContext.getDefault(); SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( sslContext, new String[]{"TLSv1.2", "TLSv1.3"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier()); CloseableHttpClient httpClient = HttpClientBuilder.create() .setSSLSocketFactory(sslSocketFactory) // 定期清理闲置连接,避免复用异常路由 .evictExpiredConnections() .evictIdleConnections(30, TimeUnit.SECONDS) .build();
3. JVM层面禁用DNS缓存
通过JVM参数强制每次请求重新解析域名,避免缓存IP导致的异常:
-Dsun.net.inetaddr.ttl=0 -Dsun.net.inetaddr.negative.ttl=0
sun.net.inetaddr.ttl=0:设置DNS解析结果缓存时间为0,每次请求都重新解析sun.net.inetaddr.negative.ttl=0:设置失败的DNS解析缓存时间为0
4. 检查Spring WS目标URL配置
确保WebServiceTemplate的目标地址始终使用DNS名称,避免代码逻辑中被替换为IP:
webServiceTemplate.setDefaultUri("https://g.i.t.n.c.com/your-service-endpoint");
验证方式
添加JVM参数-Djavax.net.debug=ssl:handshake:verbose,查看ClientHello消息中的SNI扩展,确认请求始终携带正确的DNS名称g.i.t.n.c.com。
内容的提问来源于stack exchange,提问作者Eljah
相关产品推荐
相关产品推荐

