如何解决JSP调用Java类连接HTTPS时的SSLHandshake失败异常
PKIX路径构建失败异常解决办法
异常根因
该错误是因为Glassfish服务器运行时使用的信任密钥库中,没有你所请求的HTTPS站点的根证书/中级证书,导致SSL握手时无法验证站点证书合法性。你本地直接运行Java类时使用的是JDK默认的cacerts信任库,而Glassfish默认使用自身独立的信任库,和JDK的信任库不互通,所以会出现本地运行正常、部署到Glassfish后报错的差异。
正式解决步骤(生产环境可用)
- 第一步:导出目标站点的SSL证书
通过浏览器访问目标HTTPS站点,点击地址栏的锁图标,依次选择「证书」-「详细信息」-「导出」,将证书导出为X.509格式(后缀通常为.cer/.crt),保存为site-cert.cer文件。 - 第二步:将证书导入Glassfish使用的信任库
Glassfish 5.1.0默认信任库路径为${Glassfish安装目录}/glassfish/domains/domain1/config/cacerts.jks,默认密码为changeit。如果你的Glassfish使用了自定义域名或修改过信任库密码,请对应替换路径和密码。
执行JDK自带的keytool命令完成导入:
keytool -import -alias site-cert -file 你保存的site-cert.cer文件路径 -keystore ${Glassfish安装目录}/glassfish/domains/domain1/config/cacerts.jks -storepass changeit
执行时出现是否信任证书的提示,输入yes确认即可。
如果操作后仍报错,可以额外把证书导入你使用的JDK 1.8.0_301的默认信任库,路径为${JDK安装目录}/jre/lib/security/cacerts,默认密码同样是changeit,导入命令和上述一致,仅替换keystore路径即可。
- 第三步:重启Glassfish服务器
导入完成后必须重启Glassfish实例,新的信任证书配置才会生效。
测试环境临时解决方案(禁止生产环境使用)
如果是临时测试,可在发起HTTPS连接前添加绕过SSL证书校验的代码,避免证书校验失败:
// 信任所有证书的TrustManager TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) { } public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) { } } }; // 安装信任所有证书的SSLContext SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); // 绕过主机名校验 HostnameVerifier allHostsValid = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
这段代码需要放在你调用openConnection()方法之前执行。
内容的提问来源于stack exchange,提问作者ICL Sales EXIMON
相关产品推荐
相关产品推荐

