我们正在从 Mule 3.9.0 升级到 Mule 4.5.0(社区版)。我们有一些 Mule 连接器,它们充当我们的应用程序和 Internet 上使用 SOAP 的第三方之间的桥梁。这是我们正在尝试做的事情的一个例子:
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" basePath="/base" doc:name="HTTP Listener Configuration" />
<http:request-config name="HTTP_Request_Configuration" host="www.dneonline.com" port="80" doc:name="HTTP Request Configuration" />
<flow name="bridgeFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/app" allowedMethods="POST, GET" doc:name="Mule Listener" />
<cxf:proxy-service namespace="http://tempuri.org/" service="Calculator" payload="envelope" wsdlLocation="bridge.wsdl" soapVersion="1.2" doc:name="CXF" />
<http:request config-ref="HTTP_Request_Configuration" path="/calculator.asmx" method="POST" doc:name="Outside Requester" />
</flow>
在此示例中,http:listener 组件收到 SOAP 请求以添加 2 个数字。 http:request 组件将 SOAP 信封转发到外部服务,该服务对 2 个数字进行简单的数学计算。 cxf:proxy-service 允许 Mule 将其端点公开为基于 SOAP 的 Web 服务。它引用的bridge.wsdl文件是来自http://www.dneonline.com/calculator.asmx?wsdl的wsdl的副本,删除了我们不关心的内容。
在 Mule 4 中,cxf 组件已被弃用,因此没有简单的迁移路径。我一直在尝试使用 apikit-soap:router 组件来替换 cxf:proxy-service 和 wsc:consume 组件来替换 http:request。这是我到目前为止所拥有的:
<http:listener-config name="api-httpListenerConfig" basePath="/base">
<http:listener-connection host="0.0.0.0" port="8081" />
</http:listener-config>
<apikit-soap:config name="soapkit-config" wsdlLocation="bridge.wsdl" service="Calculator" port="CalculatorSoap12" />
<wsc:config name="Web_Service_Consumer_Config">
<wsc:connection soapVersion="SOAP12" wsdlLocation="http://www.dneonline.com/calculator.asmx?wsdl" service="Calculator" port="CalculatorSoap12" address="http://www.dneonline.com/calculator.asmx" />
</wsc:config>
<flow name="api-main">
<http:listener config-ref="api-httpListenerConfig" path="/app" allowedMethods="POST, GET" doc:name="Mule Listener" />
<apikit-soap:router config-ref="soapkit-config">
<apikit-soap:attributes><![CDATA[#[%dw 2.0
output application/java
---
{
headers: attributes.headers,
method: attributes.method,
queryString: attributes.queryString
}]]]></apikit-soap:attributes>
</apikit-soap:router>
</flow>
<flow name="Add:\soapkit-config">
<ee:transform doc:name="Transform Message">
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
output application/xml
ns ns0 http://tempuri.org/
---
{
ns0#Add: {
ns0#intA: payload.body.ns0#Add.ns0#intA default 0,
ns0#intB: payload.body.ns0#Add.ns0#intB default 0
}
}]]></ee:set-payload>
</ee:message>
</ee:transform>
<wsc:consume config-ref="Web_Service_Consumer_Config" operation="Add" doc:name="Outside Consumer" />
</flow>
如果我在 wsc:consume 组件后面放置一个记录器,我可以看到它确实有效。外部服务被正确调用并返回正确的答案。问题是 wsc:consume 组件在有效负载中返回以下内容:
{
body:<AddResponse xmlns="http://tempuri.org/"><AddResult>579</AddResult></AddResponse>,
headers: [],
attachments: []
}
...但我需要的是:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<AddResponse xmlns="http://tempuri.org/">
<AddResult>579</AddResult>
</AddResponse>
</soap:Body>
</soap:Envelope>
另一个问题是需要 ee:transform 将 apikit-soap:router 的响应映射到 wsc:consume 组件识别的请求格式。在我们的一些 SOAP 服务中,请求正文包含数百个元素。绘制所有这些地图充其量也是乏味的。如果我能让 apikit-soap:router 组件返回 XML SOAP Envelope,我想我可以用 http:request 组件替换 wsc:consume,并且不需要任何转换。
有什么建议吗?
Web 服务使用者的设计使用户不必处理 SOAP 的复杂性。它故意不提供对 SOAP 详细信息和内部结构(如 CXF)的访问。如果您需要这种级别的控制,则需要使用您选择的某些 Java SOAP 框架在 Java 中实现您自己的 Web 服务调用,并使用 Java 模块来调用它。或者,您可以使用 Mule SDK 针对您的特定用例创建自己的自定义连接器。
话虽如此,如果您只需要向消息添加基本的 SOAP 信封,则可以使用 DataWeave 转换来完成此操作:
%dw 2.0
output application/xml
ns soap http://www.w3.org/2003/05/soap-envelope
---
soap#Envelop: {
soap#Body: read(payload.body, "application/xml")
}
我假设
payload.body
是一个包含 XML 的字符串。如果它是一个对象,则删除 read()
函数。
输出:
<?xml version='1.0' encoding='UTF-8'?>
<soap:Envelop xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<AddResponse xmlns="http://tempuri.org/">
<AddResult>579</AddResult>
</AddResponse>
</soap:Body>
</soap:Envelop>
如果有效负载使用其他命名空间,您可以添加它们。