从不同线程对同一服务器使用 HttpsUrlConnection 时出现 SSLProtocolException

SSLProtocolException when using HttpsUrlConnection against same server from separate threads

这两天我一直在抓耳挠腮。在这一点上欢迎任何指点或大胆的猜测。

我在 Tomcat 8.5 中有 2 个单独的 Web 应用程序 运行,使客户端 https 连接到同一服务器(Sales Force 沙箱)的不同 URL。

第一个加载的任何一个都可以正常工作,但第二个在连接时失败

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

上面注明的5可以随机2431。消息也可以是 Unknown record type...

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

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

总是在 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 只是将任何未知证书导入当前信任库并重新加载自身。我多年来一直在使用它,没有任何问题。无论如何,它只会在第一次看到新的不受信任的证书时做一些特别的事情。

非常感谢!

所以,要回答这个问题,是的,这应该可行。它在我的旧版本 jdk 8 update 102 中没有,但在版本 8 update 172 中肯定有。

我不太明白 "only second instance affected behavior" 但它肯定与不存在的无限强度策略文件有关。设置这些解决了问题。

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

谢谢大家