【问题标题】:javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake during web service communicaitonjavax.net.ssl.SSLHandshakeException:Web 服务通信期间握手期间远程主机关闭连接
【发布时间】:2026-01-04 11:05:02
【问题描述】:

当我尝试通过 Internet 对 Web 服务进行 HTTPS 发布时,我收到 javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake 异常。但相同的代码适用于其他互联网托管的 Web 服务。我尝试了很多东西,没有任何帮助。我在这里发布了我的示例代码。谁能帮我解决这个问题?

public static void main(String[] args) throws Exception {

    String xmlServerURL = "https://example.com/soap/WsRouter";
    URL urlXMLServer = new URL(xmlServerURL);
    // URLConnection supports HTTPS protocol only with JDK 1.4+ 
    Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(
            "xxxx.example.com", 8083));
    HttpURLConnection httpsURLConnection = (HttpURLConnection) urlXMLServer
            .openConnection(proxy);
    httpsURLConnection.setRequestProperty("Content-Type","text/xml; charset=utf-8");
    //httpsURLConnection.setDoInput(true);
    httpsURLConnection.setDoOutput(true);
    httpsURLConnection.setConnectTimeout(300000);
    //httpsURLConnection.setIgnoreProxy(false);
    httpsURLConnection.setRequestMethod("POST"); 
    //httpsURLConnection.setHostnameVerifier(DO_NOT_VERIFY); 
    // send request
    PrintWriter out = new PrintWriter(
            httpsURLConnection.getOutputStream());
    StringBuffer requestXML = new StringBuffer();
    requestXML.append(getProcessWorkOrderSOAPXML());   
    // get list of user     
    out.println(requestXML.toString()); 
    out.close();
    out.flush();
    System.out.println("XML Request POSTed to " + xmlServerURL + "\n");
    System.out.println(requestXML.toString() + "\n"); 
    //Thread.sleep(60000);  
    // read response

    BufferedReader in = new BufferedReader(new InputStreamReader( 
            httpsURLConnection.getInputStream()));
    String line;
    String respXML = "";
    while ((line = in.readLine()) != null) {
        respXML += line;
    }
    in.close();

    // output response
    respXML = URLDecoder.decode(respXML, "UTF-8"); 
    System.out.println("\nXML Response\n");
    System.out.println(respXML);
}

完整的堆栈跟踪:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
       at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:946)
       at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
       at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
       at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
       at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
       at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
       at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1091)
       at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
       at com.labcorp.efone.vendor.TestATTConnectivity.main(TestATTConnectivity.java:43)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
       at sun.security.ssl.InputRecord.read(InputRecord.java:482)
       at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:927)
       ... 8 more

其实这里有两种情况。当我作为一个独立的 Java 程序工作时,我遇到了上述异常。但是当我尝试在 weblogic 应用程序服务器中执行时,出现以下异常:任何线索可能是什么原因?

java.io.IOException: Connection closed, EOF detected
    at weblogic.socket.JSSEFilterImpl.handleUnwrapResults(JSSEFilterImpl.java:637)
    at weblogic.socket.JSSEFilterImpl.unwrapAndHandleResults(JSSEFilterImpl.java:515)
    at weblogic.socket.JSSEFilterImpl.doHandshake(JSSEFilterImpl.java:96)
    at weblogic.socket.JSSEFilterImpl.doHandshake(JSSEFilterImpl.java:75)
    at weblogic.socket.JSSEFilterImpl.write(JSSEFilterImpl.java:448)
    at weblogic.socket.JSSESocket$JSSEOutputStream.write(JSSESocket.java:93)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
    at java.io.FilterOutputStream.flush(FilterOutputStream.java:140)
    at weblogic.net.http.HttpURLConnection.writeRequests(HttpURLConnection.java:192)
    at weblogic.net.http.HttpURLConnection.getInputStream(HttpURLConnection.java:433)
    at weblogic.net.http.SOAPHttpsURLConnection.getInputStream(SOAPHttpsURLConnection.java:37)
    at com.labcorp.efone.service.impl.WorkOrderServiceImpl.processATTWorkOrder(ATTWorkOrderServiceImpl.java:86)
    at com.labcorp.efone.bds.WorkOrderBusinessDelegateImpl.processATTWorkOrder(WorkOrderBusinessDelegateImpl.java:59)
    at com.labcorp.efone.actions.ATTWorkOrderAction.efonePerformForward(ATTWorkOrderAction.java:41)
    at com.labcorp.efone.actions.EfoneAction.efonePerformActionForward(EfoneAction.java:149)
    at com.labcorp.efone.actions.EfoneAction.execute(EfoneAction.java:225)
    at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:484)
    at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:274)
    at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482)
    at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:525)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:751)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:844)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:280)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:254)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:136)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:341)
    at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:25)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at com.labcorp.efone.security.EfoneAuthenticationFilter.doFilter(EfoneAuthenticationFilter.java:115)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3367)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3333)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
    at weblogic.servlet.provider.WlsSubjectHandle.run(WlsSubjectHandle.java:57)
    at weblogic.servlet.internal.WebAppServletContext.doSecuredExecute(WebAppServletContext.java:2220)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2146)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2124)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1564)
    at weblogic.servlet.provider.ContainerSupportProviderImpl$WlsRequestExecutor.run(ContainerSupportProviderImpl.java:254)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:295)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:254)
Exception: java.io.IOException: Connection closed, EOF detected

【问题讨论】:

  • 你能发布完整的堆栈跟踪吗?
  • 许多可能的原因中的另一个可能是断开或连接质量非常低
  • 如果你使用另一个程序来测试你的 web 服务,比如 curl 或 soap-ui,会发生什么?我有类似的问题,它适用于 curl 但不适用于我的 Java 运行时(servicemix)。我怀疑它也可能是不包含服务器证书的客户端“cacert”。
  • 如果有人通过 gradle 到达此页面,这不是 OP 所要求的,请确保将 JAVA_HOME 设置为 Java 8 或更高版本。

标签: java ssl webservice-client


【解决方案1】:

我认为您缺少证书。

您可以尝试使用 InstallCerts 应用生成它们。在这里你可以看到如何使用它: https://github.com/escline/InstallCert

获得证书后,需要将其放在 jdk 主目录中的安全目录下,例如:

C:\Program Files\Java\jdk1.6.0_45\jre\lib\security

让我知道它是否有效。

【讨论】:

  • 两个链接都关闭了
  • @kane 我已经更新了链接......顺便说一句,我的回答并没有试图解释如何生成证书,而是将它们放在哪里。我将该链接添加为上下文信息,以防 OP 想要更深入地挖掘证书生成。
【解决方案2】:

还没有答案,但评论太多了。这显然不是服务器证书问题;症状是完全不同的。从系统的 POV 来看,握手期间服务器似乎正在关闭。有两种可能:

服务器确实正在关闭,这是对 SSL/TLS 协议的违反,虽然是相当轻微的;服务器可能无法与您握手的原因有很多,但它应该首先发送一个致命警报,您的 JSSE 或 weblogic 等价物应该指出这一点。在这种情况下,如果您能够(并且被允许)与知识渊博的服务器管理员进行通信,那么服务器日志中可能会有一些有用的信息。或者你可以尝试在你的客户端机器上安装一个网络监视器,或者一个足够近的,它可以看到你所有的流量;我个人喜欢 www.wireshark.org。但这通常只表明在 ClientHello 之后立即关闭,这并没有缩小范围。你没有说你是否应该并且已经为这个服务器配置了一个“客户端证书”(实际上是密钥和证书,以 Java privateKeyEntry 的形式);如果服务器要求这样做并且不正确,则一些服务器可能将其视为攻击并故意通过关闭来违反协议,即使它们应该正式发送警报。

或者,网络中的某个中间件(通常是防火墙或据称透明的代理)决定它不喜欢您的连接并强制关闭。您使用的代理是一个明显的嫌疑人;当您说“相同的代码”适用于其他主机时,请确认您的意思是通过 same 代理(不仅仅是代理)并使用 HTTPS(不明确的 HTTP)。如果不是这样,请尝试通过代理使用 HTTPS 测试其他主机(您不需要发送完整的 SOAP 请求,只需一个 GET / 如果足够的话)。如果可以,请尝试在不使用代理的情况下进行连接,或者可能使用其他代理,然后通过代理将 HTTP(不是 S)连接到主机(如果两者都支持 clear)并查看这些是否有效。

如果您不介意发布实际主机(但绝对不是任何身份验证凭据),其他人可以尝试。或者您可以访问 www.ssllabs.com 并要求他们测试服务器(不发布结果);这将尝试几种常见的 SSL/TLS 连接变体,并报告它看到的任何错误以及任何安全漏洞。

【讨论】:

    【解决方案3】:

    我遇到了类似的问题,发现我打错了端口。修复端口后效果很好。

    【讨论】:

      【解决方案4】:

      将证书添加到 Java\jdk\jre\lib\security 文件夹对我有用。如果您使用的是 Chrome,请单击绿色灯泡 [https://support.google.com/chrome/answer/95617?p=ui_security_indicator&rd=1] 并将证书保存在安全文件夹中。

      【讨论】:

        【解决方案5】:

        感谢大家分享您的答案和示例。相同的独立程序通过小改动和添加下面的代码行对我有用。

        在这种情况下,密钥库文件是由网络服务提供商提供的。

        // Small changes during connection initiation.. 
        
        // Please add this static block 
        
              static {
        
                HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier()
        
                    {   @Override
        
                public boolean verify(String hostname, SSLSession arg1) {
        
                // TODO Auto-generated method stub
        
                        if (hostname.equals("X.X.X.X")) {
        
                            System.out.println("Return TRUE"+hostname);
        
                            return true;
        
                        }
        
                        System.out.println("Return FALSE");
        
                        return false;
        
                      }
                       });
                 }
        
        
        String xmlServerURL = "https://X.X.X.X:8080/services/EndpointPort";
        
        
        URL urlXMLServer = new URL(null,xmlServerURL,new sun.net.www.protocol.https.Handler());
        
        
        HttpsURLConnection httpsURLConnection = (HttpsURLConnection) urlXMLServer               .openConnection();
        
        // Below extra lines are added to the same program
        
        //Keystore file 
        
         System.setProperty("javax.net.ssl.keyStore", "Drive:/FullPath/keystorefile.store");
        
         System.setProperty("javax.net.ssl.keyStorePassword", "Password"); // Password given by vendor
        
        //TrustStore file
        
        System.setProperty("javax.net.ssl.trustStore"Drive:/FullPath/keystorefile.store");
        
        System.setProperty("javax.net.ssl.trustStorePassword", "Password");
        

        【讨论】:

          【解决方案6】:

          我在使用 Java 1.6 时遇到了这个问题。在 Java 1.7 下运行修复了我对这个问题的特殊表述。我认为根本原因是我连接的服务器必须需要比 1.6 下可用的更强大的加密。

          【讨论】:

            【解决方案7】:

            我在 MacBook 中使用通过 Keychain 导出的 p12,但是它在我的 java-apns 服务器代码上不起作用。我必须做的是使用我已经生成的 pem 密钥创建一个新的 p12 密钥,如 here 所述:

            openssl pkcs12 -export -in your_app.pem -inkey your_key.pem -out your_app_key.p12
            

            然后更新了新 p12 文件的路径,一切正常。

            【讨论】:

              【解决方案8】:

              我在 glassfish 应用服务器和 Oracle JDK/JRE 中遇到了类似的问题,但在 Open JDK/JRE 中没有。

              连接到 SSL 域时,我总是遇到:

              javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
              ...
              Caused by: java.io.EOFException: SSL peer shut down incorrectly
              

              我的解决方案是安装 Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files,因为服务器只理解默认情况下不包含在 Oracle JDK 中的证书,只有 OpenJDK 包含它们。 安装后一切正常。


              JCE 7:http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html

              JCE 8:http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

              【讨论】:

                【解决方案9】:

                我遇到了同样的错误,但在我的情况下,这是由 Intellij IDE 中的 DEBUG 模式引起的。调试减慢了库的速度,然后服务器在握手阶段结束了通信。标准的“RUN”完美运行。

                【讨论】:

                  【解决方案10】:

                  Java 7 默认使用 TLS 1.0,如果不接受该协议,可能会导致此错误。我在 Tomcat 应用程序和不再接受 TLS 1.0 连接的服务器上遇到了这个问题。我加了

                  -Dhttps.protocols=TLSv1.1,TLSv1.2
                  

                  到 Java 选项并修复它。 (Tomcat 运行的是 Java 7。)

                  【讨论】:

                  • 我应该在哪里添加那行代码?在哪个文件里面?你能告诉目录路径吗?
                  • 这不是代码,它是调用 Java 可执行文件时设置的 Java 选项的一部分。确切的答案将取决于您的操作系统和程序。对于本例中的 Windows 上的 Tomcat,运行 Tomcat7w 将帮助您入门,然后修改 Java 选项。在其他情况下,您将选项添加到初始化文件中,或者对于 java.exe 命令行,将其添加到那里。如果您不熟悉 Java 选项,我肯定会建议您研究 Java 选项,而不是盲目地添加它们。一个好的开始是docs.oracle.com/javase/7/docs/technotes/tools/windows/java.html
                  • @EricaKane - 很高兴有一个答案。但是,我们如何调试这个问题并找出原因是什么? (即我们如何得出您的解决方案?)
                  • 如果您正在处理一个面向公众的网站,您可以使用 SSL Labs 或其他工具来查看他们将接受哪种协议。如果他们不再接受 TLS 1.0(坦率地说,大多数人不接受)并且您使用的是 Java 7,那么您将需要实现这一点。至于我最初是如何专门调试的,我已经不记得了。
                  • 这似乎仍然适用于 Java 8 和 Java Web Start。刚刚将 <property name="https.protocols" value="TLSv1.1,TLSv1.2"/> 添加到 JNLP 文件中以使 Web Start 再次运行...
                  【解决方案11】:

                  在我的情况下,我遇到了这个问题,因为我给服务器一个不存在的证书,由于配置文件中的拼写错误。服务器没有抛出异常,而是像往常一样继续并向客户端发送了一个空证书。因此,可能值得检查以确保服务器提供了正确的响应。

                  我在使用 Jersey 客户端连接服务器时遇到了这个错误。我解决它的方法是调试库并看到它在尝试读取的那一刻确实收到了 EOF。我还尝试使用网络浏览器进行连接,得到了相同的结果。

                  只是写在这里,以防它最终帮助任何人。

                  【讨论】:

                    【解决方案12】:

                    我曾经遇到过同样的问题。我认为是因为 URL

                    String xmlServerURL = "https://example.com/soap/WsRouter";

                    检查它是否正确??

                    javax.net.ssl.SSLHandshakeException是因为以下原因导致服务器无法连接到指定的URL-

                    • 要么网站的身份未经验证。
                    • 服务器的证书与 URL 不匹配。
                    • 或者,服务器的证书不受信任。

                    【讨论】:

                    • 这个 SSLHandshakeException 不是由这些事情引起的。
                    【解决方案13】:

                    我遇到了同样的问题并通过添加解决了它:

                    System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
                    

                    openConnection 方法之前。

                    【讨论】:

                    • 我更喜欢这种解决方案而不是投票最多的解决方案:)
                    【解决方案14】:

                    诊断问题的第一步是启动客户端 - 如果您自己运行服务器,服务器的私有测试实例 - 通过使用 VM 选项启动 Java:

                    -Djavax.net.debug=all
                    

                    另见https://blogs.oracle.com/java-platform-group/entry/diagnosing_tls_ssl_and_https

                    【讨论】:

                      【解决方案15】:

                      你可以在下面的代码中写下你当前的java程序

                      System.setProperty("https.protocols", "TLSv1.1");

                      System.setProperty("http.proxyHost", "proxy.com");

                      System.setProperty("http.proxyPort", "911");

                      【讨论】:

                        【解决方案16】:

                        我使用 Java 8 运行我的应用程序,并且 Java 8 将安全证书带入了它的信任库。然后我切换到 Java 7 并将以下内容添加到 VM 选项中:

                        -Djavax.net.ssl.trustStore=C:\<....>\java8\jre\lib\security\cacerts
                        

                        我只是指出了证书所在的位置。

                        【讨论】:

                          【解决方案17】:

                          这就是解决我的问题的方法。

                          如果您尝试使用调试器,请确保您的断点不在 URL 或 URLConnection 上,只需将断点放在 BufferReader 或 while 循环内。

                          如果没有任何效果,请尝试使用 apache 库 http://hc.apache.org/index.html

                          无需 SSL,无需 JDK 更新,甚至无需设置属性,只是简单的技巧 :)

                          【讨论】:

                            【解决方案18】:

                            你将如何解决它是通过去

                            1. 设置

                            2. 搜索“网络”

                            3. 选择“使用 IDEA 常规代理设置作为默认 Subversion”

                            【讨论】:

                              【解决方案19】:

                              根据https://kb.informatica.com/solution/23/Pages/69/570664.aspx 添加此属性有效

                              CryptoProtocolVersion=TLSv1.2

                              【讨论】:

                                【解决方案20】:

                                TLSv1.2 ALERT: fatal, handshake_failure 的基础上,我在使用此线程previos answer 调试后获得

                                -Djavax.net.debug=all

                                我去了https://www.ssllabs.com/,发现 Web 服务器需要 SSLv3 连接,该连接已于 2015 年 6 月弃用,并在 JDKu31 Release notes 弃用

                                我在该行编辑了 ${java_home}/jre/lib/security/java.security

                                jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize EC keySize

                                jdk.tls.disabledAlgorithms=RC4, DES, MD5withRSA, DH keySize EC keySize

                                作为最后一步,我得到了这个错误

                                sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target [javax.net.ssl.SSLHandshakeException]
                                

                                我用java keytool修复了这个安装证书,遵循这个答案PKIX path building failed” and “unable to find valid certification path to requested target”

                                【讨论】:

                                  【解决方案21】:

                                  我在指定 https url 并在同一个 url 中明确指定 http 端口(而不是 https 端口)时收到此错误。删除显式端口 :8080 为我解决了这个问题。

                                  【讨论】: