问题背景
1/Oerror on POSTrequestfor "xxx.com/resource/Ro…: PKIX path building failed:sun.security.provider.certpath.SunCertPathBuilderException: unable to find validcertification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unableto find valid certification path to requested target
问题解析
这个错误本质上是:
Java 在发起 HTTPS 请求时,无法验证目标网站的 SSL 证书链。
你这个报错里最关键的一句是:
PKIX path building failed
unable to find valid certification path to requested target
说明:
- Java 客户端不信任对方证书
- 或者对方证书链不完整
- 或者 JVM cacerts 里缺少对应根证书
- 或者用了自签名证书
- 或者网关/代理替换了证书
你这个请求目标是:
https://d.ceekeeapi.com/huilianyi/resource/getHotelRoomRateList
属于典型第三方接口 SSL 握手失败。
一、先明确:这不是代码业务错误
很多人会误判:
- 不是 JSON 错
- 不是 HTTP 400
- 不是参数问题
- 不是 Spring RestTemplate 问题
- 不是 POST 请求问题
而是:
TLS/SSL 证书信任链问题
发生在:
HTTP 请求真正发出去之前
即:
SSL Handshake 阶段
二、错误拆解(非常关键)
你的异常链:
SSLHandshakeException
-> ValidatorException
-> SunCertPathBuilderException
逐层含义:
1. SSLHandshakeException
说明:
HTTPS 握手失败
Java 与服务器建立 TLS 通信失败。
2. ValidatorException
说明:
证书校验失败
Java 不认可服务器返回的证书。
3. SunCertPathBuilderException
这是核心。
意思:
Java 无法构建完整可信证书链
即:
服务器证书
↓
中间证书
↓
根证书
其中某一环缺失或不可信。
三、最常见的 7 个原因
原因1:服务器没配完整证书链(最常见)
很多 Nginx / 网关:
只配置了:
ssl_certificate xxx.crt
但:
缺少 intermediate certificate
于是:
浏览器能访问(因为浏览器自动补全)
但:
Java 不行。
这是 Java 最常见 SSL 坑。
原因2:对方用了自签名证书
比如:
test 环境
内网环境
UAT 环境
证书不是正规 CA 签发。
Java 默认不信。
原因3:JDK 太老
比如:
JDK 1.8.0_121
里面根证书库太旧。
现在很多证书:
- Let's Encrypt
- DigiCert
- GlobalSign
老 JDK 不认。
原因4:公司代理替换 HTTPS 证书
比如:
- 蓝盾
- ZScaler
- 企业网关
- 抓包代理
会:
中间人代理 HTTPS
Java 不认识代理证书。
原因5:容器里的 cacerts 缺失
Docker 镜像里:
ca-certificates 不完整
尤其:
- alpine
- 精简 JRE
- distroless
很容易出问题。
原因6:目标网站证书过期
虽然少见,但必须检查。
原因7:SNI/TLS版本问题
极少见。
比如:
- TLS1.0 被禁
- 老 JDK 不支持 TLS1.2
- SNI 域名识别失败
四、最快排查方案(生产级)
第一步:浏览器打开目标地址
直接访问:
https://d.ceekeeapi.com
看:
- 是否证书告警
- 是否证书过期
第二步:openssl 查看完整证书链(最关键)
Linux 执行:
openssl s_client -showcerts -connect d.ceekeeapi.com:443
重点看:
Certificate chain
如果只有一段:
0 s:
没有:
1 s:
2 s:
基本就是:
中间证书没配
第三步:检查 JVM 版本
执行:
java -version
如果太老:
建议升级:
JDK8u301+
第四步:验证 JVM 是否信任该证书
执行:
keytool -list -cacerts
查看是否存在对应根证书。
五、真正的解决方案(按优先级)
方案1:让对方修复证书链(最佳方案)
这是正确方案。
让接口提供方:
正确配置:
fullchain.pem
而不是:
server.crt
Nginx 示例:
ssl_certificate fullchain.pem;
ssl_certificate_key privkey.pem;
方案2:升级 JDK(非常有效)
很多 SSL 问题:
升级 JDK 直接解决。
建议:
JDK8u301+
JDK11+
JDK17+
方案3:导入证书到 cacerts
适合:
- 内网系统
- 自签名证书
- 临时处理
步骤1:下载证书
浏览器导出:
cer/crt
步骤2:导入 JVM
keytool -import -alias huilianyi \
-file huilianyi.cer \
-keystore $JAVA_HOME/lib/security/cacerts
默认密码:
changeit
方案4:代码里自定义 TrustStore
Spring Boot:
-Djavax.net.ssl.trustStore=truststore.jks
-Djavax.net.ssl.trustStorePassword=123456
六、千万别这么干(危险)
很多文章会教:
TrustAll
IgnoreSSL
NoopHostnameVerifier
即:
跳过 SSL 校验
生产环境非常危险。
等于:
任何中间人证书都信任
支付系统尤其不能这么做。
七、如果这是突然出现的
重点怀疑:
1. 对方换证书了
最常见。
尤其:
Let's Encrypt 自动续期。
2. 服务器迁移
新机器没配 fullchain。
3. JDK 更新导致算法不兼容
比如:
SHA1 被禁
4. Docker 镜像变化
尤其:
FROM alpine
八、你这个问题的高概率结论
从异常特征看:
大概率是:
目标服务证书链不完整
因为:
PKIX path building failed
是典型:
intermediate certificate missing
问题。
尤其第三方 API 非常常见。
九、建议你这样处理(最稳)
优先顺序:
1. openssl 检查证书链
2. 升级 JDK
3. 联系第三方修复 fullchain
4. 临时导入证书
不要一上来:
忽略 SSL 校验
这是很多系统后面留下安全事故的根源。