在使用 Spring Boot + RestTemplate 调用 HTTPS 接口时,很多同学会遇到类似下面的报错:
javax.net.ssl.SSLHandshakeException:
PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
这类错误通常意味着:JVM 无法信任目标服务返回的证书。
一、为什么会出现 PKIX path building failed?
PKIX path building failed
的意思是 证书链校验失败,JVM 在校验证书时没有找到可信的路径。常见原因有以下几种:
1. JDK 版本过旧
较早的 JDK(如 JDK8u101 之前)默认内置的 CA 根证书库较老。
如果目标网站使用了新 CA(例如 Let's Encrypt 2021 年更新过根证书),老 JDK 可能无法识别。
2. 服务器证书链不完整
有些服务器只配置了 站点证书,但忘记安装 中间证书。
浏览器会自动帮你补全中间证书,所以能正常访问;
但 JVM 不会自动补全,导致校验失败。
3. 证书域名不匹配
如果访问
https://example.com
,但证书只签发给了api.example.com
,也会校验失败。
4. 使用了自签名证书
内网测试时常见,需要手动导入证书到 JDK 信任库。
二、如何排查?
检查证书链是否完整
openssl s_client -connect yourdomain.com:443 -showcerts
如果只输出一段证书而没有中间 CA,说明配置不完整。
检查域名是否匹配
openssl s_client -connect yourdomain.com:443 | openssl x509 -noout -text | grep DNS:
看 SAN 字段里是否包含你访问的域名。
检查 JDK 版本
java -version
建议 JDK8 至少升级到 8u202+ 或者直接使用 JDK11/17。
三、解决方案
方案一:升级 JDK(推荐)
如果你使用的是公有 CA 签发的证书(DigiCert、GlobalSign、Let's Encrypt 等),一般不需要手动导入证书。
只要 JDK 足够新,并且目标服务器配置了完整证书链,就可以正常使用。
方案二:修复服务器证书链
如果你是目标服务的维护方,确保服务器正确安装了 完整证书链:
站点证书
中间证书
根证书(通常不需要手动安装)
Nginx 示例配置:
ssl_certificate fullchain.pem; # 包含站点证书 + 中间证书
ssl_certificate_key privkey.pem;
方案三:导入证书到 JDK 信任库(自签名或内部 CA)
如果必须调用自签名 HTTPS 服务,可以手动导入证书:
keytool -import -alias myserver \
-keystore $JAVA_HOME/jre/lib/security/cacerts \
-file server.crt
默认密码:changeit
方案四:跳过 SSL 验证(仅限开发测试)
在测试环境,可以让 RestTemplate 忽略证书校验:
public static RestTemplate insecureRestTemplate() throws Exception {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setHttpClient(HttpClients.custom()
.setSSLContext(sslContext)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build());
return new RestTemplate(factory);
}
四、总结
如果是 公有 CA 签发的证书,通常不需要额外配置,只要:
JDK 版本足够新
目标服务器安装了完整证书链
就能解决。
如果是 内部/自签名证书,需要手动导入到 JDK 信任库。
开发环境临时调试,可以使用 跳过 SSL 验证的 RestTemplate,但千万不要在生产使用。