【问题标题】:Remote SOAP web service keeps breaking connection远程 SOAP Web 服务不断断开连接
【发布时间】:2017-05-15 08:35:26
【问题描述】:

简短说明

我正在使用 JBoss SwitchYard 连接到安全的远程 SOAP Web 服务。请求发出后出于某种原因;远程 Web 服务正在停止任何进一步的通信;所以我没有收到回复。

问题

我需要一个想法或解决方案,这可能是这里的问题。

错误

原因:java.net.SocketException:SocketException 调用 https://**********.asmx:来自服务器的文件意外结束

说明和注释

  • 远程 Web 服务正在使用自签名证书;我已将服务器证书导入我的本地信任库 + 我还有其他证书(在我的密钥库中)以向远程服务器标识我自己。
  • 感谢 -Djavax.net.debug=all SSL 调试日志和 Wireshark 日志我知道客户端和服务器都进行了成功的 SSL 握手并且客户端已成功发送一个请求。
  • 服务器还使用 IP 过滤来允许直接通信,并且我的 IP 被列入白名单。
  • 如果我尝试通过 SoapUI 发送相同的 XML 请求,它可以正常工作并且我会收到响应。您应该考虑到 SoapUI 只使用密钥库;它设置为始终信任远程服务,因此不需要或使用信任库。
  • 现在是有趣的部分。如果我使用 Fiddler(免费 Web 调试代理)作为我的 JBoss SwitchYard 和远程 Web 服务(查看发生了什么)之间的“中间人”,突然一切正常。
  • 直接连接和使用 Fiddler 作为代理的唯一区别在于,在实际连接中使用 Connection = Keep-Alive 标头参数,而在 Fiddler 的情况下,Proxy-Connection = Keep-Alive 参数被使用。我不知道是否还有其他显着差异。
  • 如果我在 SoapUI 中手动更改这些标头参数,我仍然会收到成功的响应。仅当我缺少 SOAPActionContent-Type 标头参数时,连接才会失败,但它们在每种情况下都存在(并且相同)。
  • 当我通过 Wireshark 观察到这种通信时,我能看到的唯一区别是远程服务器正在停止进一步的通信(当 JBoss Switchyard 应用程序直接与远程 Web 服务通信时) .
  • 我无权访问远程日志,也无权获取它们。所以我在瞎忙。
  • 在每种情况下(有或没有 Fiddler)我都使用公司代理来访问远程 Web 服务。此代理没有问题,因为其他 SwitchYard 应用程序运行良好。

工具

  • JBoss EAP 6.4
  • JBoss SwitchYard 2.0.1.redhat-621159

【问题讨论】:

  • http 级别的传输编码是什么?我在使用类似效果的分块编码(虽然没有 ssl)时遇到了一些问题。
  • 您是否尝试过更改加密协议和/或密码?
  • 你能分享可用的日志和 Wireshark 捕获吗?
  • 远程服务在 Azure 上吗?如果是这样,请参阅这个 SO 问题:stackoverflow.com/questions/33789895/…

标签: java web-services fiddler jboss-eap-6 switchyard


【解决方案1】:

异常

java.net.SocketException:来自服务器的文件意外结束

这个异常意味着服务器已经接受了你的连接,这意味着你的 SSL 握手确实成功了。但是服务器在您获得响应之前关闭了连接(通过 TCP 重置或 fin)。

复位通常在两种情况下发送:

  • 超过配置的持久连接(保持连接)
  • 服务器重启后失去连接

通常,一个持久连接有两个配置:

Keep-Alive: timeout=15, max=100

timeout 表示以秒为单位的时间,max 表示最大请求数。

连接与代理连接

让我们比较一下您描述的三种不同情况:

  • SoapUI:成功; ?
  • 直接连接:失败;连接 = 保持活动状态
  • 提琴手:成功;代理连接 = 保持活动状态

在第三种情况下,如果我理解正确,您的持久连接是从客户端到代理以及从代理到服务器不清楚。

 client----->Proxy----->server

建议

  • 尝试从响应中获取服务器的长连接配置(如here),查看直连是否超过时间或次数限制
  • 尽量不使用持久连接:java -Dhttp.keepalive=false

参考

【讨论】:

    【解决方案2】:

    问题可能是由于 SOAP 请求的标头无效或格式无效,您可以尝试如下代码

    1 你需要HeaderHandlerResolver

     public class HeaderHandlerResolver implements HandlerResolver {
    
            public List<Handler> getHandlerChain(PortInfo portInfo) {
                List<Handler> handlerChain = new ArrayList<Handler>();
    
                HeaderHandler hh = new HeaderHandler();
    
                handlerChain.add(hh);
    
                return handlerChain;
            }
        }
    

    然后你需要添加 HeaderHandler

     public class HeaderHandler implements SOAPHandler<SOAPMessageContext> {
    
            public boolean handleMessage(SOAPMessageContext smc) {
    
                Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    
                if (outboundProperty.booleanValue()) {
    
                    SOAPMessage message = smc.getMessage();
    
                    try {
    
                        SOAPEnvelope envelope = smc.getMessage().getSOAPPart().getEnvelope();
    
                        SOAPHeader header = envelope.getHeader();
                        header.setPrefix("soapenv");
                        header.setAttribute("xmlns:wsa", "http://www.w3.org/2005/08/addressing");
    
                        SOAPElement security =
                                header.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
    
                        SOAPElement usernameToken =
                                security.addChildElement("UsernameToken", "wsse");
                        usernameToken.addAttribute(new QName("xmlns:wsu"), "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
    
                        SOAPElement username =
                                usernameToken.addChildElement("Username", "wsse");
                        username.addTextNode("USERNAME");
    
                        SOAPElement password =
                                usernameToken.addChildElement("Password", "wsse");
                        password.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
                        password.addTextNode("PASSWORD");
    
                        SOAPElement encode =
                                usernameToken.addChildElement("Nonce", "wsse");
                        encode.setAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
                        encode.addTextNode(generateNonce());
    
                        Calendar createdTime = new GregorianCalendar(TimeZone.getTimeZone("IST"));
                        Date todayDate = createdTime.getTime();
                        todayDate.setTime(todayDate.getTime()-20000000);
    
                        SOAPElement created = usernameToken.addChildElement("Created", "wsu");
                        created.addTextNode(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'").format(todayDate));
    
                        SOAPElement action = header.addChildElement("Action", "wsa");
                        //YOUR ACTION URL SHOULD BE in BELOW Text Content
                        action.setTextContent("SET HERE YOUR ACTION URL");
    
                        message.saveChanges();
                        message.writeTo(System.out);
                        System.out.println("");
    
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
    
                } else {
                    try {
    
                        //This handler does nothing with the response from the Web Service so
                        //we just print out the SOAP message.
                        SOAPMessage message = smc.getMessage();
                        message.writeTo(System.out);
                        System.out.println("");
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
    
    
                return outboundProperty;
    
            }
    
            public Set getHeaders() {
                return null;
            }
    
            public boolean handleFault(SOAPMessageContext context) {
                return true;
            }
    
            public void close(MessageContext context) {
            }
    
            private static String generateNonce() throws NoSuchAlgorithmException, NoSuchProviderException, UnsupportedEncodingException {
                String dateTimeString = Long.toString(new Date().getTime());
                byte[] nonceByte = dateTimeString.getBytes();
                return Base64.encodeBase64String(nonceByte);
            }
        }
    

    现在终于是调用 SOAP 服务的主类

    public class SoapClientClass {
    
        public static void main(String[] args) {
    
            ImplService service = new ImplService();
            HeaderHandlerResolver handlerResolver = new HeaderHandlerResolver();
            service.setHandlerResolver(handlerResolver);
    
            ResponseClass port = service.getPortClass();
    
            Response response = null;
            try {
                response = port.getServerMehotd("Params");
            } catch (PolicyException_Exception e) {
                e.printStackTrace();
            } catch (ServiceException_Exception e) {
                e.printStackTrace();
            }
    
            }
        }
    }
    

    另外,请确保您从 wsdl 文件生成的代码是最新的并且服务器位置 url 也是正确的。

    希望它能解决你的问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-23
      相关资源
      最近更新 更多