web-services - 将 CXF 与 Apache Camel 结合使用时,如何设置 WS-Addressing MessageId header ?

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

我正在调用需要 WS-Addressing SOAP header 的 Web 服务。我正在使用 Apache Camel 和 CXF 来调用 Web 服务。当我使用 Web 服务的 WSDL 配置 CXF 端点时,它足够智能,可以自动添加 WS-Adressing SOAP header ,但我需要设置自定义 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”。我需要设置自定义值。

我尝试按照添加“国际”和“用户”等其他 header 的方式添加 MessageId header ,但框架的某些部分覆盖了该值。

// 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 header 的文档,但我不知道如何将其应用于 Apache Camel。 Apache Camel CXF documentation也没有特别提到 WS-Addressing。

最佳答案

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

The CXF documentation说:

The CXF org.apache.cxf.ws.addressing.impl.AddressingPropertiesImpl object can be used to control many aspects of WS-Addressing including the Reply-To:

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说:

How to propagate a camel-cxf endpoint’s request and response context

CXF client API provides a way to invoke the operation with request and response context. If you are using a camel-cxf endpoint producer to invoke the outside web service, you can set the request context and get response context with the following code:

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"


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

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

关于web-services - 将 CXF 与 Apache Camel 结合使用时,如何设置 WS-Addressing MessageId header ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54115116/

相关文章:

ios - 关闭应用程序时如何在后台运行快速应用程序?

web-services - Get 和 post 方法与 HTTP 和 REST 的区别

web-services - Angular 2 服务 : where to keep the data

c++ - 在 C/C++ 上传输数据的最佳(最简单)方法是什么

java - 如何将正则表达式添加到 Camel 路线?

c# - WCF 反序列化的对象属性的空值

php - 未捕获的 SoapFault 异常 : [WSDL] SOAP-ERROR: Parsing WSDL Couldn't load from 'http://88. XXX.XXX.XXX:8080/

c# - 无法在 C# 中登录我的 netsuite 帐户

apache-camel - 如何使用 Websockets 将 Spark Streaming 数据从服务器端发送到客户端?

rabbitmq - Camel RabbitMQ 连接器在使用之前会读取数千条消息