首页 > 解决方案 > 从不同线程对同一服务器使用 HttpsUrlConnection 时出现 SSLProtocolException

问题描述

2 天来的大部分时间里,我一直在挠头。在这一点上,欢迎任何指针或疯狂的猜测。

我在 Tomcat 8.5 中运行了 2 个单独的 web 应用程序,使客户端 https 连接到同一服务器上的不同 url(销售人员沙箱)。

无论它们中的哪一个首先加载都可以,但第二个在连接时失败

javax.net.ssl.SSLProtocolException: Handshake message sequence violation, 5

上面提到5的可以是随机2431。也可以留言Unknown record type...

引擎盖下似乎有某种共享资源,因为两个 web 应用程序都可以自己正常工作。在我看来,就好像我的客户端在服务器重用以前打开的连接时尝试启动新的握手?

调用disconnect()连接没有任何区别,发送"Connect: close"标头也没有。还尝试使用所有响应数据并关闭流但没有成功。

异常总是在conn.getOutputStream().

这是一个线程的作用:

final HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
conn.setRequestProperty("Content-Length", String.valueOf(reqBytes.length));
conn.setRequestProperty("Connection", "close");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
     os.write(reqBytes);
     os.flush();
}

final StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String line;
while ((line = br.readLine()) != null) {
     b.append(line).append(NEWLINE);
}
conn.disconnect();

这是另一个:

URL url = new URL(reportingUrl);
byte[] reqBytes = report.toString(2).getBytes("UTF-8");
final HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
 conn.setRequestMethod("POST");
 conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
 conn.setRequestProperty("Content-Length", String.valueOf(reqBytes.length));
 conn.setRequestProperty("Connection", "close");
 conn.setDoOutput(true);
 try (OutputStream os = conn.getOutputStream()) {
     os.write(reqBytes);
     os.flush();
 }
 InputStream in = conn.getInputStream();
 byte[] buffer = new byte[1024];
 while (in.read(buffer) > -1) {}
 conn.disconnect();

最后,这是我在服务器启动时进行的一些自定义:

TrustManager[] tlsTrustManagers = new TrustManager[]{new ReloadableX509TrustManager(null, null)};
 SSLContext ctx = SSLContext.getInstance("TLSv1.1");
 ctx.init(null, tlsTrustManagers, null);
 ctx = SSLContext.getInstance("TLSv1.2");
 ctx.init(null, tlsTrustManagers, null);
 SSLContext.setDefault(ctx);

ReloadableX509TrustManager只需将任何未知证书导入当前信任库并重新加载即可。我多年来一直在使用它,没有任何问题。无论如何,它只会在每次看到新的不受信任的证书时做一些特别的事情。

非常感谢!

标签: javahttpsurlconnection

解决方案


所以,要回答这个问题,是的,这应该有效。它在我的旧 jdk 8 update 102 中没有,但在版本 8 update 172 中确实如此。

我不太了解“只有第二个实例影响的行为”,但它肯定与不存在的无限强度策略文件有关。设置这些解决了这个问题。

现在这不是问题,因为jdk 8 update 161

不管怎么说,还是要谢谢你


推荐阅读