Java进程默认只信任cacerts中的CA根证书,调用自签名HTTPS接口会抛SSL异常;需用keytool将目标证书导入对应JDK的cacerts文件,密码为changeit,注意JDK路径、IDE/构建工具JDK一致性及SNI和证书链完整性。

OpenJDK 开发环境里,Java 进程默认只信任 cacerts 里已有的 CA 根证书。如果你调用的是自签名 HTTPS 接口(比如本地联调、内网服务、企业微信测试域名),会直接抛 SSLHandshakeException 或 CertPathBuilderException ——这不是代码写错了,是 JVM 拒绝和“身份不明”的服务器握手。
怎么把目标 HTTPS 证书加进 OpenJDK 的信任库
核心动作就是用 keytool 把目标服务的证书(.crt 或 .cer)导入到当前 JDK 使用的 cacerts 文件中。注意:必须用你项目实际运行所用的 JDK 的 keytool 和 cacerts,否则白忙一场。
- 先确认 JDK 路径:
echo $JAVA_HOME(Linux/macOS)或echo %JAVA_HOME%(Windows) - 证书文件要先拿到手:可以用浏览器导出(访问目标地址 → 锁图标 → 证书 → 复制为 Base64 X.509),也可以用
openssl s_client -connect host:port 2>/dev/null | openssl x509 -out target.cer - 执行导入命令(JDK 8–17 均适用):
keytool -import -alias myapi -file target.cer -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit -noprompt
- 如果提示
Permission denied,说明没权限写入cacerts,Linux/macOS 加sudo,Windows 用管理员权限打开终端
为什么用 changeit 作为 -storepass
cacerts 是 JDK 自带的信任库,默认密码就是 changeit。改过密码的环境极少,硬要改反而容易在 CI/CD 或多 JDK 切换时出错。除非你明确知道这个 JDK 的 cacerts 密码被重置过,否则不要动它。
- 验证是否导入成功:
keytool -list -v -keystore $JAVA_HOME/lib/security/cacerts | grep myapi - 导入后,所有走这个 JDK 启动的 Java 进程(Spring Boot、Gradle、Maven、IDE 内嵌 JVM)都会自动信任该证书
- 别名(
-alias)只要不和其他已存在条目冲突即可,不需要和域名一致
常见失败场景和对应检查点
导入完还是报证书异常?大概率卡在这几个地方:
- IDE(IntelliJ/Eclipse)用了自己 bundled 的 JRE/JDK,而不是系统
$JAVA_HOME—— 检查 IDE 的Project Structure → SDK和Run Configuration → JRE - 构建工具(如 Maven)单独配置了
JAVA_HOME,和终端不一致 —— 在终端执行mvn -version看它用的是哪个 JDK - 目标接口用了 SNI(Server Name Indication),但导出的证书不是它实际返回的那个 —— 用
openssl s_client -connect host:port -servername host显式指定 SNI 名再导出 - 证书链不完整,只导出了 leaf cert,没导中间 CA —— 浏览器导出时选「复制整个证书路径」,或用
openssl s_client -showcerts手动拼全
最易被忽略的一点:OpenJDK 不同版本的 cacerts 路径可能不同(JDK 8 是 $JAVA_HOME/jre/lib/security/cacerts,JDK 11+ 是 $JAVA_HOME/lib/security/cacerts),但 keytool -list -keystore 能直接告诉你它正在读哪个文件 —— 别猜,先查。

















