【踩坑系列】使用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+端口访问),在和第三方确认没有域名访问后,在浏览器里输入第三方的接口地址,发现证书有问题:

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

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

3.解决方案

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

首先,新建HttpClient工具类:

java 复制代码
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的代码改为如下所示:

ini 复制代码
CloseableHttpClient httpClient = HttpClientUtils.createIgnoreCertClient();

注意事项:

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

xml 复制代码
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>
相关推荐
小梁努力敲代码2 小时前
java数据结构--List的介绍
java·开发语言·数据结构
摸鱼的老谭2 小时前
构建Agent该选Python还是Java ?
java·python·agent
lang201509282 小时前
Spring Boot 官方文档精解:构建与依赖管理
java·spring boot·后端
夫唯不争,故无尤也3 小时前
Tomcat 启动后只显示 index.jsp,没有进入你的 Servlet 逻辑
java·servlet·tomcat
zz-zjx3 小时前
Tomcat核心组件全解析
java·tomcat
Deschen3 小时前
设计模式-外观模式
java·设计模式·外观模式
why技术3 小时前
从18w到1600w播放量,我的一点思考。
java·前端·后端
夫唯不争,故无尤也4 小时前
JavaWeb流式传输速查宝典
java·流式传输
苏小瀚5 小时前
算法---位运算
java·算法
Camel卡蒙5 小时前
数据结构——二叉搜索树Binary Search Tree(介绍、Java实现增删查改、中序遍历等)
java·开发语言·数据结构