You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨域Tomcat Servlet通过HttpsURLConnection连接SSL握手异常解决求助

这个SSL握手错误我之前也碰到过,本质是你的JVM不信任目标服务器用的Let's Encrypt根证书——毕竟旧版JDK的默认信任库(cacerts)里并没有包含ISRG Root X1这根证书。下面给你几个靠谱的解决方案,按需选择:

解决方案一:手动导入Let's Encrypt根证书到JVM信任库

这是全局生效的方案,适合所有运行在该JVM下的应用:

  • 首先获取ISRG Root X1证书:
    你可以用openssl命令从目标服务器导出证书链:
    openssl s_client -connect your-target-domain:443 -showcerts
    
    找到输出中标记为ISRG Root X1的证书块,复制从-----BEGIN CERTIFICATE-----到-----END CERTIFICATE-----的全部内容,保存为isrgrootx1.crt文件。
  • 用keytool命令将证书导入JVM的信任库:
    keytool -importcert -alias isrgrootx1 -file isrgrootx1.crt -keystore $JAVA_HOME/jre/lib/security/cacerts
    
    注意:默认信任库密码是changeit,如果你的JDK路径不同(比如OpenJDK的jre位置),要替换成对应的路径;操作可能需要管理员权限(加sudo)。
  • 重启你的Tomcat服务器,让配置生效。
解决方案二:代码中自定义信任管理器(无需修改全局JVM配置)

如果不想改动全局JVM设置,可以在代码里指定信任Let's Encrypt的根证书,示例如下:

import javax.net.ssl.*;
import java.io.*;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;

public class HttpsClient {
    public static void main(String[] args) throws Exception {
        // 加载ISRG Root X1证书文件(你需要提前把证书放到项目资源里)
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream certInputStream = new FileInputStream("path/to/isrgrootx1.crt");
        java.security.cert.Certificate cert = cf.generateCertificate(certInputStream);
        certInputStream.close();

        // 创建自定义KeyStore并添加证书
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(null, null);
        ks.setCertificateEntry("isrgrootx1", cert);

        // 初始化TrustManagerFactory
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ks);

        // 创建SSLContext并设置自定义TrustManager
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);

        // 打开HTTPS连接并设置自定义SSLSocketFactory
        HttpsURLConnection conn = (HttpsURLConnection) new URL("https://your-target-domain/servlet-path").openConnection();
        conn.setSSLSocketFactory(sslContext.getSocketFactory());

        // 后续的请求逻辑(比如获取输出流)
        OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
        // ... 你的其他代码
    }
}

⚠️ 注意:绝对不要在生产环境使用“信任所有证书”的简化方案(比如跳过证书验证),这会引入严重的安全风险。

解决方案三:升级JDK版本(长期最优解)

从Oracle JDK 8u101版本开始,官方已经把ISRG Root X1证书加入了默认信任库;OpenJDK的部分发行版(比如Adoptium/Temurin)也在较新版本中包含了该证书。如果你的JDK版本比较旧,直接升级到符合要求的版本,就能自动解决这个问题,不用做额外配置。

额外注意事项
  • 确认目标服务器的证书链配置完整:Let's Encrypt的证书通常需要搭配中间证书一起使用,如果目标Tomcat没有正确配置发送完整的证书链,即使你导入了根证书,依然可能出现握手失败。
  • 如果使用的是OpenJDK,有些精简版可能默认不包含商业根证书,这种情况下即使升级版本,也可能需要手动导入证书,或者选择包含完整根证书的OpenJDK发行版。

内容的提问来源于stack exchange,提问作者stefano errani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:40:45