【踩坑系列】使用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>
相关推荐
bing_15822 分钟前
JVM happens-before 原则有哪些?
java·jvm
Thanwind22 分钟前
JVM运行时数据区域(Run-Time Data Areas)的解析
java·jvm·jdk·jmm
goTsHgo37 分钟前
Java的对象头:原理与源码详解
java·开发语言
hie9889437 分钟前
如何配置 Java 安全管理器来避免访问控制异常
java·python·安全
wgc2k1 小时前
Java游戏服务器开发流水账(2)开发中Maven的管理
java·服务器·游戏
LUCIAZZZ1 小时前
ElasticSearch基本概念
java·大数据·elasticsearch·搜索引擎·中间件·操作系统
冼紫菜1 小时前
如何使用责任链模式优雅实现功能(滴滴司机、家政服务、请假审批等)
java·开发语言·设计模式·责任链模式
Uranus^1 小时前
Spring AI 入门(持续更新)
java·人工智能·spring·ai
程序员buddha3 小时前
用Maven定位和解决依赖冲突
java·maven