意外的HttpURLConnection连接行为

时间:2016-10-20 00:13:37

标签: java sockets https applet network-protocols

我正在将Applet转换为桌面应用程序,其中一个内部程序服务包括一个SOAP客户端,旨在将信息发送到远程服务器。以下是负责此流程的代码:

package my.package.app.utils;

import my.package.app.main.MainClass;
import my.package.app.org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SoapClient {

    public static JSONObject callMethod(String path, String method, Object... args) {
        HttpURLConnection connection = null;
        String            data       = null;
        try {
            data = parseXML(method, args);

            MainClass.debug("Making http POST connections to : " + path);

            URL           u  = new URL(path);
            URLConnection uc = u.openConnection();
            connection = (HttpURLConnection) uc;

            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("SOAPAction", method);
            connection.setUseCaches(false);

            OutputStream out  = connection.getOutputStream();
            Writer       wout = new OutputStreamWriter(out);

            wout.write(data);
            wout.flush();
            wout.close();

            InputStream            in  = connection.getInputStream();
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder        db  = dbf.newDocumentBuilder();
            Document               doc = db.parse(in);

            doc.getDocumentElement().normalize();

            NodeList childs       = doc.getElementsByTagName("return");
            String   responseText = childs.item(0).getTextContent();

            if ("false".equals(responseText)) {
                return null;
            }

            JSONObject response = new JSONObject(responseText);

            in.close();
            return response;

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    private static String parseXML(String method, Object... args) {

        StringBuilder xml = new StringBuilder();

        xml.append(XMLTemplates.soapHeader);
        xml.append("<ns1:");
        xml.append(method);
        xml.append(">");

        for (int i = 0; i < args.length; i++) {

            String dataType = "xsi:type=\"xsd:string\"";

            xml.append("<param");
            xml.append(i);
            xml.append(" ");

            if (args[i] instanceof Integer) {
                dataType = "xsi:type=\"xsd:integer\"";
            }

            if (args[i] instanceof Double) {
                dataType = "xsi:type=\"xsd:decimal\"";
            }

            if (args[i] instanceof Boolean) {
                dataType = "xsi:type=\"xsd:boolean\"";
            }

            xml.append(dataType);
            xml.append(">");
            xml.append(String.valueOf(args[i]));
            xml.append("</param");
            xml.append(i);
            xml.append(">");
        }

        xml.append("</ns1:");
        xml.append(method);
        xml.append(">");

        xml.append(XMLTemplates.soapFooter);

        return xml.toString();
    }

}

当使用 callMethod 时,它会在我的案例中收到一个路径字符串,其中包含带有HTTPS协议的网址,如下所示:&#34; https://fileserver.myserver.net:9000/lf_soap_document_server_main.php& #34;

使用该网址运行 callMethod 时,小程序的Java控制台会显示以下内容:

18:15:45.476-DEBUG: Making http POST connections to : https://fileserver.myserver.net:9000/lf_soap_document_server_main.php
network: Connecting https://fileserver.myserver.net:9000/lf_soap_document_server_main.php with proxy=DIRECT
network: Connecting http://fileserver.myserver.net:9000/ with proxy=DIRECT

并且该过程成功完成。

但是当从桌面应用程序版本执行相同的代码时,会发生以下情况:

18:28:29.991-DEBUG: Making http POST connections to : https://fileserver.myserver.net:9000/lf_soap_document_server_main.php
network: Connecting https://fileserver.myserver.net:9000/lf_soap_document_server_main.php with proxy=DIRECT
network: Connecting socket://fileserver.myserver.net:9000 with proxy=DIRECT
java.net.ConnectException: Connection timed out: connect

OutputStream out = connection.getOutputStream(); 被调用时,会出现问题。请注意,日志消息将URL的协议从https://更改为socket://,并且似乎也删除了最后一个斜杠(/)。

这是一个完整的例外:

java.net.ConnectException: Connection timed out: connect
  at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
  at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
  at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
  at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
  at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
  at java.net.PlainSocketImpl.connect(Unknown Source)
  at java.net.SocksSocketImpl.connect(Unknown Source)
  at java.net.Socket.connect(Unknown Source)
  at sun.security.ssl.SSLSocketImpl.connect(Unknown Source)
  at sun.net.NetworkClient.doConnect(Unknown Source)
  at sun.net.www.http.HttpClient.openServer(Unknown Source)
  at sun.net.www.http.HttpClient.openServer(Unknown Source)
  at sun.net.www.protocol.https.HttpsClient.<init>(Unknown Source)
  at sun.net.www.protocol.https.HttpsClient.New(Unknown Source)
  at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection$6.run(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection$6.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.security.AccessController.doPrivilegedWithCombiner(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
  at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.access$100(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection$8.run(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection$8.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.security.AccessController.doPrivilegedWithCombiner(Unknown Source)
  at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source)
  at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown Source)
  at my.package.app.utils.SoapClient.callMethod(SoapClient.java:42)
  at my.package.app.services.scanner.LFScanner$SoapUpload.run(LFScanner.java:746)

桌面应用程序使用Jetty创建与安全websocket服务器的连接,并在用户的计算机上创建本地websocket服务器,但它们都没有与发生问题的SoapClient类建立业务关系。 / p>

我已经测试过为连接设置了5分钟超时并读取了HttpURLConnection实例,但问题仍然在不到一分钟的时间内在桌面应用程序上发生。

我使用1.8.0_111-b14作为运行时来执行程序(applet和桌面应用程序),在Windows 10机器上,64位。

我需要知道此代码是否有任何问题,或者此处是否缺少设置以防止这种情况发生。

非常感谢任何帮助。

感谢。

1 个答案:

答案 0 :(得分:0)

我已经在一个独立的程序中测试了有问题的代码片段,只需要重现所需的最少代码,并且发现问题实际上是在服务器端,即为URL提供SOAP服务的问题。到目前为止,大多数测试都适用于其他程序,但发现SOAP url在其他程序中也存在可用性问题,而不仅仅是Java,这解释了一般的问题。

用于连接和使用SOAP服务的代码没问题,问题出在目标网址上。

我仍然不知道Java控制台在尝试访问SOAP URL时在调试信息中显示不同协议的原因,但它似乎并不是一个问题(现在)。