跨域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 -showcertsISRG Root X1的证书块,复制从-----BEGIN CERTIFICATE-----到-----END CERTIFICATE-----的全部内容,保存为isrgrootx1.crt文件。 - 用
keytool命令将证书导入JVM的信任库:
注意:默认信任库密码是keytool -importcert -alias isrgrootx1 -file isrgrootx1.crt -keystore $JAVA_HOME/jre/lib/security/cacertschangeit,如果你的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
相关产品推荐
相关产品推荐

