从不同线程对同一服务器使用 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
可以随机2
、4
、3
或1
。消息也可以是 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。
谢谢大家
这两天我一直在抓耳挠腮。在这一点上欢迎任何指点或大胆的猜测。
我在 Tomcat 8.5 中有 2 个单独的 Web 应用程序 运行,使客户端 https 连接到同一服务器(Sales Force 沙箱)的不同 URL。
第一个加载的任何一个都可以正常工作,但第二个在连接时失败
javax.net.ssl.SSLProtocolException: Handshake message sequence violation, 5
上面注明的5
可以随机2
、4
、3
或1
。消息也可以是 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。
谢谢大家