【问题标题】:Spring-WS client not setting SOAPAction headerSpring-WS 客户端未设置 SOAPAction 标头
【发布时间】:2019-01-05 01:53:53
【问题描述】:

我正在发送一个 SOAP 请求,但服务器抱怨 SOAPAction 标头为空。我认为我设置它是正确的,但显然我不是。 Wireshark 显示它没有设置。

@Test
public void testLogin() throws Exception {
    StringBuffer loginXml = new StringBuffer();
    loginXml.append("<soapenv:Envelope xmlns:soapenv=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:ns=\"http://example.com/xyz/2010/08\">");
    loginXml.append("  <soapenv:Header>");
    loginXml.append("    <ns:loginOperationDetails>");
    loginXml.append("    </ns:loginOperationDetails>");
    loginXml.append("  </soapenv:Header>");
    loginXml.append("  <soapenv:Body>");
    loginXml.append("    <ns:LogIn>");
    loginXml.append("      <ns:logInInfo>");
    loginXml.append("        <ns:CustomerAccountId>customer1</ns:CustomerAccountId>");
    loginXml.append("        <ns:Username>JDoe</ns:Username>");
    loginXml.append("        <ns:Password>abc123</ns:Password>");
    loginXml.append("      </ns:logInInfo>");
    loginXml.append("    </ns:LogIn>");
    loginXml.append("  </soapenv:Body>");
    loginXml.append("</soapenv:Envelope>");

    WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
    MessageFactory msgFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
    SaajSoapMessageFactory newSoapMessageFactory = new SaajSoapMessageFactory(msgFactory);
    webServiceTemplate.setMessageFactory(newSoapMessageFactory);

    String uri = "http://xyz.example.com/xyz_1.0/membership.svc/ws";
    webServiceTemplate.setDefaultUri(uri);

    StreamSource source = new StreamSource(new StringReader(loginXml.toString()));
    StreamResult result = new StreamResult(System.out);

    boolean resultReturned = false;
    try {
        resultReturned = webServiceTemplate.sendSourceAndReceiveToResult(source, 
            new SoapActionCallback("http://example.com/xyz/2010/08/MembershipService/LogIn"), 
            result);
    } 
    catch (SoapFaultClientException sfe) {
        logger.error("SoapFaultClientException resultReturned: " + resultReturned, sfe);
        fail();
    }
}

我从服务器返回的错误说:

500 Internal Server Error
The SOAP action specified on the message, '', does not match the HTTP SOAP Action, 'http://example.com/xyz/2010/08/MembershipService/LogIn'.

【问题讨论】:

    标签: soap soap-client spring-ws


    【解决方案1】:

    完整答案如下。

    当您使用 WebServiceTemplate 作为类与 Web 服务进行通信时,我不明白为什么,但它没有正确填充 HTTP 标头。

    一些 WSDL 有一部分说:

    <soap:operation
                soapAction="SOMELINK"
                style="document" />
    

    WebServiceTemplate 忽略了这部分。上面的错误意味着你在 header 中的soapAction 参数是空的。它不应该。与 Wireshark 核对。我做到了 - 使用了一些 Chrome Soap 客户端和 Spring。第二个的标题无效。


    要解决此问题,您需要遵循此处的第 6.2.4 节:http://docs.spring.io/spring-ws/sites/2.0/reference/html/client.html

    它所说的基本上是您自己添加标题部分,带有WebServiceMessageCallback接口。您可以在参考中阅读更多内容。

    基本上是这样结束的:

     webServiceTemplate.marshalSendAndReceive(o, new WebServiceMessageCallback() {
    
        public void doWithMessage(WebServiceMessage message) {
            ((SoapMessage)message).setSoapAction("http://tempuri.org/Action");
        }
    });
    

    您可以在哪里正确设置标题值。也为我工作。一整天的阅读。

    【讨论】:

    • 像魅力一样工作,谢谢为我节省了很多精力!
    • 不知道能不能自动完成。添加这个硬编码的值对我有用,但是用这样的东西把我的代码弄得一团糟并不是很好。
    • @Michal 你总是可以通过使用属性文件使其更加参数化。
    • 请注意,此解决方案不适用于 Soap 1.2,因为不推荐使用 SOAPAction 标头。
    • Soap 1.1 确实可以正常工作,因为未自动填写soapAction。
    【解决方案2】:

    我解决了这个问题,但从未发布过答案。这是我最终得到的效果很好:

    public WebServiceTemplate getWebServiceTemplate() throws SOAPException {
      if (webServiceTemplate == null) {
        final MessageFactory msgFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
        final SaajSoapMessageFactory newSoapMessageFactory = new SaajSoapMessageFactory(msgFactory);
        webServiceTemplate = new WebServiceTemplate(newSoapMessageFactory);
      }   
    
      return webServiceTemplate;
    }
    
    public Object sendReceive(Object requestObject, ArrayList<String> classesToMarshall, final String action)
            throws ClassNotFoundException, SoapFaultException, SoapFaultClientException, WebServiceTransportException,
            IllegalStateException, SOAPException {
    
      final WebServiceTemplate wst = getWebServiceTemplate();
    
        final SoapMarshallUtil smu = getSoapMarshallUtil();
        smu.configureMarshaller(wst, classesToMarshall);
    
        // soap 1.2
        SoapActionCallback requestCallback = new SoapActionCallback(action) {
            public void doWithMessage(WebServiceMessage message) {
                SaajSoapMessage soapMessage = (SaajSoapMessage) message;
                SoapHeader soapHeader = soapMessage.getSoapHeader();
    
                QName wsaToQName = new QName("http://www.w3.org/2005/08/addressing", "To", "wsa");
                SoapHeaderElement wsaTo =  soapHeader.addHeaderElement(wsaToQName);
                wsaTo.setText(uri);
    
                QName wsaActionQName = new QName("http://www.w3.org/2005/08/addressing", "Action", "wsa");
                SoapHeaderElement wsaAction =  soapHeader.addHeaderElement(wsaActionQName);
                wsaAction.setText(action);
            }
        };
    
        Object responseObject = wst.marshalSendAndReceive(this.uri, requestObject, requestCallback);
        return responseObject;
    }
    

    【讨论】:

      【解决方案3】:

      另一种解决方法是添加一个拦截器并在入站接收MessageContexthandleRequest()方法中设置soapAction,SoapMessage可以从中派生;

      之后,您可以轻松设置调用setSoapAction() 方法的soapAction。

      这里是拦截器类的代码:

      public class SecurityInterceptor implements ClientInterceptor {
      
          @Override
          public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
      
              SoapMessage soapMessage = (SoapMessage) messageContext.getRequest();
              soapMessage.setSoapAction("mySoapAction");    
      
              return true;
          }
      
          //TODO:: other methods and constructor..
      }
      

      当然还要将拦截器添加到WebTemplate:

      WebServiceTemplate webServiceTemplate = new WebServiceTemplate(marshaller);
      ClientInterceptor[] interceptors = new ClientInterceptor[]{new SecurityInterceptor(parameters)};
      webServiceTemplate.setInterceptors();
      webServiceTemplate.marshalSendAndReceive(uriWebService, request)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-11
        • 1970-01-01
        • 2013-01-12
        • 1970-01-01
        • 2011-05-02
        • 1970-01-01
        • 2011-03-09
        • 1970-01-01
        相关资源
        最近更新 更多