【问题标题】:Getting Error in SOAP POST request using Apache CXF but curl works使用 Apache CXF 在 SOAP POST 请求中出错,但 curl 有效
【发布时间】:2015-08-30 13:09:16
【问题描述】:

我遇到了一个非常奇怪的问题。我正在尝试通过 HTTPS 执行 SOAP POST 请求。当我从我的代码发送请求时,我收到 HTTP 500 错误。现在从 cxf 日志中,如果我复制相同的 SOAP 消息(标题和正文),我得到错误并使用简单的 curl 请求发布它,它工作正常。下面是我如何创建服务类和其他初始化

URL wsdlurl = SOAPWebServiceTransport.class.getClassLoader().
        getResource("my.wsdl");
OnlinePort service= new OnlinePortService(wsdlurl).getOnlinePortPort();
Client proxy = ClientProxy.getClient(service);

// Provides WS-Security
WSS4JOutInterceptor wss4jOut = new WSS4JOutInterceptor();
wss4jOut.setProperty("action", "UsernameToken");
wss4jOut.setProperty("user", userName);
wss4jOut.setProperty("passwordType", "PasswordText");
wss4jOut.setProperty("password", password);
wss4jOut.setProperty(WSHandlerConstants.ADD_UT_ELEMENTS,
        WSConstants.NONCE_LN + " " + WSConstants.CREATED_LN);
wss4jOut.setProperty(WSHandlerConstants.PW_CALLBACK_CLASS, ServerPasswordCallback.class.getName());

proxy.getEndpoint().getOutInterceptors().add(wss4jOut);
setConduitProperties((HTTPConduit) proxy.getConduit(),url);

在设置管道方法中,我忽略了 ssl 检查(仅用于开发环境)并设置了一些标头。

TLSClientParameters tcp = new TLSClientParameters();
tcp.setDisableCNCheck(true);
// Creating Trust Manager
TrustManager[] trustAllCerts = new TrustManager[] {
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }

        public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }
} };

tcp.setTrustManagers(trustAllCerts);
conduit.setTlsClientParameters(tcp);

HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setAllowChunking(false);
httpClientPolicy.setAccept("*/*");
httpClientPolicy.setContentType("text/xml;charset=UTF-8");
httpClientPolicy.setHost(url.split("/")[2]);
conduit.setClient(httpClientPolicy);

任何帮助都将不胜感激。

Response-Code: 500
Encoding: ISO-8859-1
Content-Type: text/html;charset=ISO-8859-1
Headers: {connection=[close], content-type=[text/html;charset=ISO-8859-1],
          Date=[Mon, 15 Jun 2015 06:42:09 GMT], Server=[Apache-Coyote/1.1],
          Set-Cookie=[JSESSIONID=FF0E4F5DCA42F700FFAC46BBD039FC20; Path=/; Secure],
          transfer-encoding=[chunked]}
Payload: 

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

> <html> <head> <meta http-equiv="Content-Type" content="text/html;
> charset=ISO-8859-1"/> <title>Error Page</title> </head> <body>Invalid
> Request </body> </html>


at org.apache.cxf.interceptor.StaxInInterceptor.handleMessage(StaxInInterceptor.java:79)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
    at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:797)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1618)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1491)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1399)
    at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:47)
    at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:188)
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:646)
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:533)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:463)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:366)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:319)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:88)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:134)
 Caused by: org.apache.cxf.interceptor.Fault: Response was of unexpected text/html ContentType.  Incoming portion of HTML stream: 

CURL 请求

curl -k --header "Content-Type: text/xml;charset=UTF-8" --header "SOAPAction:" --data @soaprequest.xml https://url

Curl log in verbose(当然改了一些url端口名0

来自服务器的错误响应

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>Error Page</title>
</head>
<body>Invalid Request
</body>
</html> 

【问题讨论】:

  • 这是客户端堆栈跟踪。你能知道服务器端发生了什么吗?我的假设是某些身份验证尝试出错并且服务器发出了 HTML 响应。在 curl 中,从 CXF 的角度来看,这并不重要:“响应是意外的文本/html” - 表示服务器端问题。
  • 不,我们不可能看到服务器端发生了什么。是的,cxf 失败了,因为它接收的是 html 响应而不是基于 soap 的 xml,但由于一些错误或验证,我得到了我猜是服务器端的异常。令人惊讶的是,具有几乎相同 http 标头的相同肥皂请求正在使用 curl。
  • 我敢打赌,您的 Content-Type 标头在发出请求之前已被覆盖,您能否检查从应用程序发送的 Post 请求标头?
  • @JacobMargason 它发送 'content-type': 'text/xml;charset=UTF-8' 我检查了它
  • 您确定您在客户端使用的 WSDL URL 是正确的 URL?

标签: java apache curl https cxf


【解决方案1】:

我最近遇到了与您类似的问题。我刚刚在依赖项中添加了 2 个工件:

    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>${cxf.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http-jetty</artifactId>
        <version>${cxf.version}</version>
    </dependency>

【讨论】:

    【解决方案2】:

    检查 WSDL URL。

    URL 必须在 ?wsdl 之前给出

    【讨论】:

      【解决方案3】:

      SOAP 适用于 xml,我可以看到您有以下错误

      Caused by: org.apache.cxf.interceptor.Fault: Response was of unexpected text/html ContentType. Incoming portion of HTML stream:

      这表示您的响应是 HTML 格式的, Response-Code: 500 Encoding: ISO-8859-1 Content-Type: text/html;chars

      所以你的 WebService 可能有问题尝试使用 SOAP UI

      此链接也将非常有用地讨论同一问题。 https://forums.mulesoft.com/questions/27468/web-service-consumer-response-was-of-unexpected-te.html

      【讨论】:

        【解决方案4】:

        尝试使用Fiddler 作为代理并比较两个请求。标头或请求正文必须有所不同。

        Fiddler 也能够解码 TLS。

        祝大家好运..

        【讨论】:

          【解决方案5】:

          转机是使用核心 java HttpURLConnection 来实现这一点。

          类似这样的方法帮助原因广告在没有任何框架的情况下发布 Web 服务调用。:

          public HttpURLConnection getHttpConn(String webservice_url) throws IOException {
          URL endpoint = new URL(webservice_url);
          URLConnection connection = endpoint.openConnection();
          HttpURLConnection httpConn = (HttpURLConnection) connection;
          byte[] encodedBytes = Base64.encodeBase64((getUsername()+":"+getPassword()).getBytes());
          httpConn.setRequestMethod(getRequestMethod());
          httpConn.setRequestProperty(HTTP_ACCEPT_ENCODING, getAccept_Encoding());
          httpConn.setRequestProperty(HTTP_CONTENT_TYPE, getContentType());
          httpConn.setRequestProperty(getContent_Length(), getContent_Length());
          httpConn.setRequestProperty(HTTP_HOST, getHost());
          httpConn.setRequestProperty(getConnection(), getConnection());
          httpConn.setRequestProperty(HTTP_COOKIE2, getCookie2());
          httpConn.setRequestProperty(HTTP_COOKIE, getCookie());
          httpConn.setRequestProperty("Authorization", "Basic "+new String(encodedBytes));
          httpConn.setDoOutput(true);
          httpConn.setDoInput(true);
          return httpConn;
          }
          

          确保在 CXF 配置文件 (cxf.xml) 中配置 http 客户端。

          如 Apache CXF 文档中所述:

          1.添加http-conduit命名空间和xsd:

          <beans ...
                 xmlns:http-conf="http://cxf.apache.org/transports/http/configuration
                 ...
                 xsi:schemaLocation="...
                     http://cxf.apache.org/transports/http/configuration
                     http://cxf.apache.org/schemas/configuration/http-conf.xsd
                 ...">
          

          2.添加http-conduit标签/元素并将RecieveTimeout/ConnectionTimeout设置为180000ms:

          <http-conf:conduit name="*.http-conduit">
                <http-conf:client 
                                ConnectionTimeout="300000"
                                ReceiveTimeout="300000"/>       
          </http-conf:conduit>
          

          【讨论】:

          • 已经尝试过使用 HttpURLConnection 并且其他一些框架没有帮助。
          【解决方案6】:

          如果你无法访问服务器上的日志,你可以尝试检查你的代码请求和curl请求是否不同。

          为此,您可以使用像tcpmon 这样的嗅探器来嗅探http 请求。

          Tcpmon 作为客户端和服务器之间的代理运行。它拦截所有请求并打印每个请求和响应的详细信息。

          【讨论】:

          • Soap 标头和消息与我从 cxf 日志中复制并使用 curl 发送的完全相同。可能是 https 的一些问题,由于使用 SSL 对消息进行加密,因此难以跟踪
          猜你喜欢
          • 2018-10-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-22
          相关资源
          最近更新 更多