【踩坑系列】使用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>
相关推荐
m0_734172428 分钟前
Python列表切片为什么不改变原列表
java
kiss strong11 分钟前
idea显示前进后退按钮
java·ide·intellij-idea
caoerzhong38 分钟前
跨境海外仓怎么管:JeeWMS 开源 Java 仓库管理系统打通头程、海外仓与尾程
java·开发语言·开源
MayBaymax43 分钟前
Elasticsearch 原理与用法
java·elasticsearch
马剑威(威哥爱编程)1 小时前
【AI全栈后端12-02】Spring Boot 跑通第一个 AI 对话接口:HR 政策问答机器人实战
java·人工智能·spring boot·机器人
IT枫斗者枫哥1 小时前
AI返回合法JSON,字段就可信吗?给抽取结果补一道业务校验
java·人工智能·后端
用户3126874877201 小时前
Java IO/NIO/AIO 演进:从 BIO 到 Netty 的底层逻辑
java
IT枫斗者枫哥1 小时前
同一个requestId换了参数,为什么不能直接返回旧结果?
java·后端
天天被压力1 小时前
【别再到处找免费股票数据API了:官方204个接口,32篇一次讲透 #06】Python实时行情总报错?五档盘口+逐笔一次跑通
java·人工智能·python
今年下半年1 小时前
【网站连通性检测】java项目telnet、curl命令的使用
java·curl·telnet