Java Netty出现“handshake_failure at remote address”错误的原因是什么?
先理清楚问题核心:你的本地环境用的JDK 1.7.0_u141已经默认支持TLS1.2,但生产环境的JDK 1.7版本大概率是较早的update版本(JDK 1.7从u131才开始默认启用TLS1.2),所以后端升级TLS1.2后生产环境连不上。下面是具体的解决步骤:
先确认生产环境的JDK版本
登录生产服务器执行命令:java -version,查看具体的update版本。如果是u131以下,有两种方向解决:要么升级JDK 1.7到最新的update版本(比如u211,这是JDK1.7的最终更新版本),要么手动开启TLS1.2支持。用JVM参数强制启用TLS1.2(最省心的方案)
如果你没法大规模修改代码,直接给Tomcat添加JVM启动参数即可:
找到Tomcat的catalina.sh(Linux环境)或者catalina.bat(Windows环境),在JAVA_OPTS配置项中加入:-Dhttps.protocols=TLSv1.2比如Linux下可以修改为:
JAVA_OPTS="$JAVA_OPTS -Dhttps.protocols=TLSv1.2"修改完成后重启Tomcat,整个应用的HTTP客户端都会默认使用TLS1.2协议连接后端。
局部代码调整方案(仅适用于特定请求异常的场景)
要是个别HTTP请求仍有问题,可以在代码中指定SSLContext使用TLS1.2:try { SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); } catch (NoSuchAlgorithmException | KeyManagementException e) { e.printStackTrace(); }不过考虑到你的代码库规模大,这个方案改动成本高,优先推荐JVM参数的方式。
检查并导入后端新证书
后端更新了SSL证书,需要确保生产环境的JDK信任该证书。执行以下命令将证书导入JDK的默认密钥库:keytool -import -alias backend-server-cert -file /path/to/your/new-cert.crt -keystore $JAVA_HOME/jre/lib/security/cacerts密钥库默认密码是
changeit,导入完成后记得重启Tomcat。验证连接有效性
可以先用OpenSSL命令测试生产服务器与后端的TLS1.2握手是否正常:openssl s_client -connect your-backend-domain:443 -tls1_2如果握手成功,说明网络和协议层面没问题;再写一个简单的Java测试类,用生产环境的JDK运行,确认应用层面能正常获取后端数据。
内容的提问来源于stack exchange,提问作者dlite922

