【踩坑系列】使用httpclient调用第三方接口返回javax.net.ssl.SSLHandshakeException异常

1. 踩坑经历

最近做了个需求,需要调用第三方接口获取数据,在联调时一直失败,代码抛出javax.net.ssl.SSLHandshakeException异常,

具体错误信息如下所示:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

2.原因分析

因为调用第三方接口的代码是复用项目中原有的工具类(基于httpclient封装),所以在确认完传参没问题后,第一时间排除了编码问题。

然后开始怀疑第三方提供的接口地址(因为竟然是IP+端口访问),在和第三方确认没有域名访问后,在浏览器里输入第三方的接口地址,发现证书有问题:

【踩坑系列】使用httpclient调用第三方接口返回javax.net.ssl.SSLHandshakeException异常

又使用Postman调用第三方接口,也是失败,提示自签名证书:

【踩坑系列】使用httpclient调用第三方接口返回javax.net.ssl.SSLHandshakeException异常

通过以上分析,可以发现出现该问题的根本原因是Java客户端不信任目标服务器的SSL证书,比如这个第三方使用的自签名证书。

3.解决方案

解决方案一般有2种,第1种方案是将服务器证书导入Java信任库,第2种方案是绕过SSL验证,这里采用第2种方案。

首先,新建HttpClient工具类:

import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients;  import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate;  public class HttpClientUtils {     public static CloseableHttpClient createIgnoreCertClient() throws NoSuchAlgorithmException, KeyManagementException {         SSLContext sslContext = SSLContext.getInstance("SSL");         sslContext.init(null, new TrustManager[]{new X509TrustManager() {             @Override             public X509Certificate[] getAcceptedIssuers() {                 return null;             }              @Override             public void checkClientTrusted(X509Certificate[] certs, String authType) {             }              @Override             public void checkServerTrusted(X509Certificate[] certs, String authType) {             }         }}, new java.security.SecureRandom());         SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);         return HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build();     } } 

然后将原来声明httpClient的代码改为如下所示:

CloseableHttpClient httpClient = HttpClientUtils.createIgnoreCertClient(); 

注意事项:

确保项目中引入了httpclient依赖:

<dependency>     <groupId>org.apache.httpcomponents</groupId>     <artifactId>httpclient</artifactId>     <version>4.5.13</version> </dependency> 

发表评论

您必须 [ 登录 ] 才能发表留言!

相关文章