【问题标题】:How do I set the WS-Addressing MessageId header when using CXF with Apache Camel?将 CXF 与 Apache Camel 一起使用时,如何设置 WS-Addressing MessageId 标头?
【发布时间】:2019-06-04 12:31:39
【问题描述】:

我正在调用一个需要 WS-Addressing SOAP 标头的 Web 服务。我正在使用 Apache Camel 和 CXF 来调用 Web 服务。当我使用 Web 服务的 WSDL 配置 CXF 端点时,它可以自动添加 WS-Adressing SOAP 标头,但我需要设置自定义 MessageId。

这是当前正在发送的消息:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <soap:Header>
        <ws:international xmlns:ws="http://www.w3.org/2005/09/ws-i18n">
            <ws:locale xmlns:ws="http://www.w3.org/2005/09/ws-i18n">en_CA</ws:locale>
        </ws:international>
        <fram:user wsa:IsReferenceParameter="true" xmlns:fram="http://wsbo.webservice.ephs.pdc.ibm.com/Framework/" xmlns:wsa="http://www.w3.org/2005/08/addressing">BESTSystem</fram:user>
        <Action soap:mustUnderstand="true" xmlns="http://www.w3.org/2005/08/addressing">http://webservice.ephs.pdc.ibm.com/Client/QueryHumanSubjects</Action>
        <MessageID soap:mustUnderstand="true" xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:945cfd10-9fd2-48f9-80b4-ac1b9f3293c6</MessageID>
        <To soap:mustUnderstand="true" xmlns="http://www.w3.org/2005/08/addressing">https://panweb5.panorama.gov.bc.ca:8081/ClientWebServicesWeb/ClientProvider</To>
        <ReplyTo soap:mustUnderstand="true" xmlns="http://www.w3.org/2005/08/addressing">
            <Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
        </ReplyTo>
    </soap:Header>
    <soap:Body>
        <ns2:queryHumanSubjectsRequest xmlns:ns2="http://wsbo.webservice.ephs.pdc.ibm.com/Client/" xmlns:ns3="http://wsbo.webservice.ephs.pdc.ibm.com/FamilyHealth/">
            <!-- stuff -->
        </ns2:queryHumanSubjectsRequest>
    </soap:Body>
</soap:Envelope>

如您所见,MessageId 值为“urn:uuid:945cfd10-9fd2-48f9-80b4-ac1b9f3293c6”。我需要设置一个自定义值。

我尝试添加 MessageId 标头,就像我添加“国际”和“用户”等其他标头一样,但框架的某些部分会覆盖该值。

// Note this doesn't work! Something overrides the value. It works for other headers.
@Override
public void process(Exchange exchange) throws Exception {

    Message in = exchange.getIn();
    List<SoapHeader> headers = CastUtils.cast((List<?>) in.getHeader(Header.HEADER_LIST));

    SOAPFactory sf = SOAPFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
    QName MESSAGE_ID_HEADER = new QName("http://www.w3.org/2005/08/addressing", "MessageID", "wsa");
    SOAPElement messageId = sf.createElement(MESSAGE_ID_HEADER);
    messageId.setTextContent("customValue");
    SoapHeader soapHeader = new SoapHeader(MESSAGE_ID_HEADER, messageId);
    headers.add(soapHeader);
}

The CXF website 有一些关于如何设置 WS-Addressing 标头的文档,但我看不到如何将其应用于 Apache Camel。 Apache Camel CXF documentation 也没有特别提到 WS-Addressing。

【问题讨论】:

    标签: web-services soap apache-camel cxf ws-addressing


    【解决方案1】:

    您发布的文档链接实际上确实包含您需要的信息,尽管如何将其应用于 Camel 并不是很明显。

    The CXF documentation 说:

    CXF org.apache.cxf.ws.addressing.impl.AddressingPropertiesImpl 对象可用于控制 WS-Addressing 的许多方面,包括回复:

    AddressingProperties maps = new AddressingPropertiesImpl();
    EndpointReferenceType ref = new EndpointReferenceType();
    AttributedURIType add = new AttributedURIType();
    add.setValue("http://localhost:9090/decoupled_endpoint");
    ref.setAddress(add);
    maps.setReplyTo(ref);
    maps.setFaultTo(ref);
    ((BindingProvider)port).getRequestContext()
            .put("javax.xml.ws.addressing.context", maps);
    

    请注意,它在“RequestContext”上设置寻址属性。

    The Apache Camel documentation 说:

    如何传播 camel-cxf 端点的请求和响应上下文

    CXF 客户端 API 提供了一种使用请求和响应上下文调用操作的方法。如果您使用 camel-cxf 端点生产者来调用外部 Web 服务,您可以使用以下代码设置请求上下文并获取响应上下文:

    CxfExchange exchange = (CxfExchange)template.send(getJaxwsEndpointUri(), new Processor() {
        public void process(final Exchange exchange) {
            final List<String> params = new ArrayList<String>();
            params.add(TEST_MESSAGE);
            // Set the request context to the inMessage
            Map<String, Object> requestContext = new HashMap<String, Object>();
            requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, JAXWS_SERVER_ADDRESS);
            exchange.getIn().setBody(params);
            exchange.getIn().setHeader(Client.REQUEST_CONTEXT , requestContext);
            exchange.getIn().setHeader(CxfConstants.OPERATION_NAME, GREET_ME_OPERATION);
        }
    });
    

    上面的例子有一些我们不需要的东西,但重要的是它向我们展示了如何设置 CXF 请求上下文。

    把它们放在一起,你会得到:

    @Override
    public void process(Exchange exchange) throws Exception {
        AttributedURIType messageIDAttr = new AttributedURIType();
        messageIDAttr.setValue("customValue");
    
        AddressingProperties maps = new AddressingProperties();
        maps.setMessageID(messageIDAttr);
    
        Map<String, Object> requestContext = new HashMap<>();
        requestContext.put(JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES, maps);
        exchange.getIn().setHeader(Client.REQUEST_CONTEXT, requestContext);
    }
    
    // org.apache.cxf.ws.addressing.JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES = "javax.xml.ws.addressing.context"
    // org.apache.cxf.endpoint.Client.REQUEST_CONTEXT = "RequestContext"
    
    

    警告:在我的路由中,我依次调用多个不同的 Web 服务。我发现在如上所示设置 RequestContext 后,Camel 开始对所有 Web 服务使用相同的 RequestContext,这导致错误:“表示消息寻址属性的标头无效,无法处理消息”。这是因为第一次之后的所有 Web 服务调用都使用了不正确的“Action”标头。

    我使用“RequestContext”Exchange 属性 将其追溯到 Apache Camel,与我们设置的标头分开,显然它优先于标头。如果我在调用后续 Web 服务之前删除此属性,CXF 会自动填写正确的 Action 标头。

    【讨论】:

      【解决方案2】:

      如果您的问题没有解决,我建议您将您的 cxf 服务与自定义拦截器结合使用。使用您的肥皂信息很容易。像这样:

      <bean id="TAXWSS4JOutInterceptorBean" name="TAXWSS4JOutInterceptorBean" class="com.javainuse.beans.SetDetailAnswerInterceptor " />
      <cxf:cxfEndpoint id="CXFTest" address="/javainuse/learn"
                       endpointName="a:SOATestEndpoint" serviceName="a:SOATestEndpointService"
                       serviceClass="com.javainuse.SOATestEndpoint"
                       xmlns:a ="http://javainuse.com">
          <cxf:binding>
              <soap:soapBinding mtomEnabled="false" version="1.2" />
          </cxf:binding>
      
          <cxf:features>
              <wsa:addressing  xmlns:wsa="http://cxf.apache.org/ws/addressing"/>
          </cxf:features>
          <cxf:inInterceptors>
      
              <ref bean="TAXWSS4JInInterceptorBean" />            
      
          </cxf:inInterceptors>
          <cxf:inFaultInterceptors>
      
          </cxf:inFaultInterceptors>
          <cxf:outInterceptors>
              <ref bean="TAXWSS4JOutInterceptorBean" />
          </cxf:outInterceptors>
          <cxf:outFaultInterceptors>
      
          </cxf:outFaultInterceptors>
      </cxf:cxfEndpoint>
      

      在拦截器中,您可以像这样设置soap标头:

      public class SetDetailAnswerInterceptor extends WSS4JOutInterceptor {
      
      public SetDetailAnswerInterceptor() {
      
      }
      
      @Override
      public void handleMessage(SoapMessage mc) {
          AttributedURIType value = new AttributedURIType();
          value.setValue("test");
          ((AddressingProperties) mc.get("javax.xml.ws.addressing.context.outbound")).setMessageID(value);
      }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-27
        • 2012-02-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-15
        相关资源
        最近更新 更多