2026家用无线投屏芯片选型深度分析:潜创微及适配品牌实用参考
2026/6/13 6:09:56
在使用Java的RestTemplate访问HTTPS接口时,如果使用IP地址而不是域名,经常会遇到以下错误:
java.security.cert.CertificateException: No subject alternative names matching IP address 111.63.81.79 found nested exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names matching IP address 111.63.81.79 found奇怪的是:使用Postman、curl等工具可以正常访问,但Java代码却报错。
HTTPS协议在建立连接时,会进行SSL证书验证,主要包括两个方面:
Subject Alternative Names (SAN)字段SSL证书中有一个字段叫Subject Alternative Names (SAN),它列出了该证书可以用于哪些域名或IP地址。例如:
Subject Alternative Names: DNS: example.com DNS: www.example.com IP Address: 192.168.1.1如果证书中没有包含你访问的IP地址(如111.63.81.79),Java就会抛出上述异常。
我们需要配置RestTemplate,让它跳过SSL证书验证。注意:这种方法只适用于开发/测试环境,生产环境应该使用正确的证书。
创建一个RestTemplateConfig配置类:
packagecom.example.zbx.config;importorg.apache.http.client.config.RequestConfig;importorg.apache.http.conn.ssl.NoopHostnameVerifier;importorg.apache.http.conn.ssl.SSLConnectionSocketFactory;importorg.apache.http.impl.client.CloseableHttpClient;importorg.apache.http.impl.client.HttpClients;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.http.client.HttpComponentsClientHttpRequestFactory;importorg.springframework.web.client.RestTemplate;importjavax.net.ssl.SSLContext;importjavax.net.ssl.TrustManager;importjavax.net.ssl.X509TrustManager;importjava.security.cert.X509Certificate;/** * RestTemplate配置类 * 配置忽略SSL证书验证,支持使用IP地址访问HTTPS接口 * @author lxy */@ConfigurationpublicclassRestTemplateConfig{/** * 创建RestTemplate Bean * 配置忽略SSL证书验证,支持使用IP地址访问HTTPS接口 * @return RestTemplate实例 */@BeanpublicRestTemplaterestTemplate(){try{// 创建完全信任所有证书的TrustManagerTrustManager[]trustAllCerts=newTrustManager[]{newX509TrustManager(){@OverridepublicX509Certificate[]getAcceptedIssuers(){returnnull;}@OverridepublicvoidcheckClientTrusted(X509Certificate[]certs,StringauthType){// 不进行任何检查,信任所有客户端证书}@OverridepublicvoidcheckServerTrusted(X509Certificate[]certs,StringauthType){// 不进行任何检查,信任所有服务器证书}}};// 创建SSL上下文,使用自定义的TrustManagerSSLContextsslContext=SSLContext.getInstance("TLS");sslContext.init(null,trustAllCerts,newjava.security.SecureRandom());// 创建SSL连接工厂,忽略主机名验证(包括IP地址验证)SSLConnectionSocketFactorysslSocketFactory=newSSLConnectionSocketFactory(sslContext,NoopHostnameVerifier.INSTANCE);// 创建请求配置RequestConfigrequestConfig=RequestConfig.custom().setConnectTimeout(10000)// 连接超时10秒.setConnectionRequestTimeout(10000)// 请求超时10秒.setSocketTimeout(30000)// 读取超时30秒.build();// 创建HttpClientCloseableHttpClienthttpClient=HttpClients.custom().setSSLSocketFactory(sslSocketFactory).setDefaultRequestConfig(requestConfig).evictExpiredConnections().evictIdleConnections(30,java.util.concurrent.TimeUnit.SECONDS).build();// 创建请求工厂HttpComponentsClientHttpRequestFactoryfactory=newHttpComponentsClientHttpRequestFactory();factory.setHttpClient(httpClient);factory.setConnectTimeout(10000);factory.setConnectionRequestTimeout(10000);factory.setReadTimeout(30000);// 创建RestTemplatereturnnewRestTemplate(factory);}catch(Exceptione){thrownewRuntimeException("创建RestTemplate失败",e);}}}TrustManager[]trustAllCerts=newTrustManager[]{newX509TrustManager(){@OverridepublicvoidcheckServerTrusted(X509Certificate[]certs,StringauthType){// 不进行任何检查,信任所有服务器证书}// ... 其他方法}};这个X509TrustManager会跳过所有证书验证,包括:
SSLContextsslContext=SSLContext.getInstance("TLS");sslContext.init(null,trustAllCerts,newjava.security.SecureRandom());使用自定义的TrustManager初始化SSL上下文。
SSLConnectionSocketFactorysslSocketFactory=newSSLConnectionSocketFactory(sslContext,NoopHostnameVerifier.INSTANCE// 不验证主机名);NoopHostnameVerifier.INSTANCE会跳过主机名验证,这样即使证书中没有对应的IP地址也能通过验证。
确保你的pom.xml中包含以下依赖:
<!-- HttpClient4 (for RestTemplate SSL configuration) --><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId></dependency>配置完成后,直接使用RestTemplate即可,无需额外代码:
@AutowiredprivateRestTemplaterestTemplate;publicvoidcallApi(){Stringurl="https://111.63.81.79:10091/api/endpoint";ResponseEntity<String>response=restTemplate.postForEntity(url,request,String.class);// 处理响应...}如果必须在生产环境使用,建议:
// 只信任特定的证书KeyStoretrustStore=KeyStore.getInstance("JKS");trustStore.load(newFileInputStream("truststore.jks"),"password".toCharArray());TrustManagerFactorytrustManagerFactory=TrustManagerFactory.getInstance("X509");trustManagerFactory.init(trustStore);SSLContextsslContext=SSLContext.getInstance("TLS");sslContext.init(null,trustManagerFactory.getTrustManagers(),null);可能的原因:
对于开发环境,可以设置JVM参数(不推荐):
-Dcom.sun.net.ssl.checkRevocation=false但这种方法不够灵活,建议使用配置类的方式。
不会。这个配置只影响使用RestTemplate的HTTPS请求,HTTP请求不受影响。
在代码中添加日志,观察是否还有证书验证错误:
log.info("RestTemplate配置完成,SSL验证已禁用");如果不再出现CertificateException,说明配置生效了。
RestTemplate跳过SSL证书验证X509TrustManager+NoopHostnameVerifier