我找到了一个更清洁/更好的解决方案 - 它只是上述答案的增强版本。
主要挑战是让 SOAP WSDL 和服务端点(上下文 URI)工作,而不像在代理服务方法上那样强制它工作。请注意,如果您可以使用 WSO2 团队建议的 contextURI (/services//),则无需执行任何这些操作。标准文档将包含您需要的所有详细信息。
逻辑是:
定义 3 个序列(我将它们分成三个,但您也可以将所有这些都放在一个序列中)。
主序列(标准内置序列 - 如果请求不遵循 ESB 中已经定义的代理服务规则,这是获取所有流量的序列)。在主序列中,我们只是将所有传入请求路由到另一个进行过滤/条件路由的序列。
<sequence name="main">
<in>
<log level="full"/>
<sequence key="routing_seq"/>
</in>
<out>
<send/>
</out>
<description>The main sequence for the message mediation</description>
</sequence>
* routing_sequence*
就像在第一个答案中一样,我们将根据请求中的上下文 URI 将传入的请求路由到其他特殊序列。
<sequence xmlns="http://ws.apache.org/ns/synapse" name="routing_seq">
<in>
<log level="custom">
<property xmlns:ns="http://org.apache.synapse/xsd" name="Current URL" expression="get-property('To')"/>
</log>
<conditionalRouter continueAfter="false">
<conditionalRoute breakRoute="false" asynchronous="false">
<condition>
<or>
<match type="url" regex="/firstService/10\.06/.*"/>
<match type="url" regex="/firstServiceVariant/.*"/>
</or>
</condition>
<target sequence="firstService_seq"/>
</conditionalRoute>
<conditionalRoute breakRoute="false" asynchronous="false">
<condition>
<match type="url" regex="/secondService.*"/>
</condition>
<target sequence="second_seq"/>
</conditionalRoute>
</conditionalRouter>
</in>
</sequence>
* firstservice_seq*
现在我们准备好处理传入的请求 - 请注意,我们在上一步中将应用程序标识为“firstservice”。您可以在此处接收两种请求 - 一种是针对 WSDL 的,另一种是肥皂请求
<sequence xmlns="http://ws.apache.org/ns/synapse" name="firstService_seq">
<in>
<property name="REST_URL_POSTFIX" scope="axis2" action="remove"/>
<!-- We are checking whether the request ends with a ?wsdl or .xsd -->
<!-- For that we are using the context URI present in the 'To' field -->
<!-- if it is a wsdl or xsd request, we are converting it to a HTTP GET method -->
<!-- and sending to the final endpoint. All soap operation requests are sent as HTTP POST -->
<switch xmlns:ns="http://org.apache.synapse/xsd" source="get-property('To')">
<case regex=".*(?:\?[Ww][Ss][Dd][Ll]|\.[Xx][Ss][Dd])\s*$">
<property name="HTTP_METHOD" value="GET"/>
<property name="messageType" value="text/xml"/>
<send receive="wsdl_transformer_seq">
<endpoint key="local-enrty-firstservice-ep-key"/>
</send>
<drop/>
</case>
<!-- default means non-wsdl/non-xsd - which means a regular soap operation on the service -->
<default>
<property name="HTTP_METHOD" value="POST"/>
<send>
<endpoint key="local-enrty-firstservice-ep-key"/>
</send>
</default>
</switch>
</in>
<out>
<send/>
</out>
</sequence>
希望您阅读序列定义中的注释。如您所见,我将 wsdl 和 xsd 请求转换为 HTTP GET 以避免在应用层出现任何混淆,否则可能会从流中的某个位置注入一些垃圾 SOAP 正文部分)。
所以基本上,我们检查包含上下文 URI 的“To”属性,例如 /firstservice/10.06/service?WSDL(如果它是 WSDL 请求)或 /firstservice/10.06/service - 如果它是 SOAP 请求。根据该值,我们决定如何处理请求。
请注意 wsdl 逻辑中的以下部分:
<send receive="wsdl_transformer_seq">
<endpoint key="local-enrty-firstservice-ep-key"/>
</send>
<drop/>
</send>
发生的情况是,当我们从端点提取 wsdl(我将很快解释)时,schemaLocation 和soap:address 字段包含处理请求的实际服务器实例的信息(主机名和端口)。这是不希望的结果,因为您将内部详细信息暴露给客户和其他人。所以我们应该掩盖它。这样做的方法是使用 WSO2 中的一个特殊功能。在发送中,您可以指定另一个序列,该序列将在发送结果发送到客户端之前接收它。这或多或少就像您<out>
在序列中定义一个部分。由于我们不希望所有请求都发生这种特殊操作,因此我们没有定义仅应用于 wsdl/xsd 请求的特殊序列。在wsdl_transformer_seq,我们使用 XSLT 更改 wsdl 或 xsd 响应中存在的主机名和端口。
wsdl_transformer_seq
<sequence name="wsdl_transformer_seq">
<xslt xmlns:ns="http://org.apache.synapse/xsd"
key="xslt-url-manipulator"
source="/"/>
<send/>
</sequence>
请注意,我将这些条目(例如 xslt 转换器)外部化并通过本地条目注册表加载它们。
<localEntry key="xslt-url-manipulator"
src="file:repository/myapp/resources/transform/url-in-wsdl-transform.xslt"/>
现在url-in-wsdl-transform.xslt的内容
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:param name="newURL">https://services.mycompany.com</xsl:param>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="soap:address/@location">
<xsl:attribute name="location">
<xsl:value-of select="replace(.,'https?://[^/]*',$newURL)"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="xs:import/@schemaLocation">
<xsl:attribute name="schemaLocation">
<xsl:value-of select="replace(.,'https?://[^/]*',$newURL)"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
请注意上面 xslt 中的名称 - https://services.mycompany.com。您可以将其更改为您想要的任何内容,并且 wsdl 和 xsd 中的 schemaLocation 和 soap:address 字段现在将在 host:port 区域中使用它
最后是端点local-enrty-firstservice-ep-key
请注意,这也是一个外部加载的文件 - 就像上面的 xslt 条目一样。所以我只会发布实际外部文件的内容。
这是一个艰难的 cookie,我不得不深入研究 WSO2 源代码并找出一些“未记录”的功能。好吧,它在 WSO2 世界中是“未记录的”,但由于 WSO2 使用了第三方库,该库具有许多未在 WSO2 中发布的功能,因此另有记录。请注意,端点指向应用层实例,我们使用循环算法将流量分配到可用的应用层实例。
<endpoint xmlns="http://ws.apache.org/ns/synapse">
<loadbalance algorithm="org.apache.synapse.endpoints.algorithms.RoundRobin">
<endpoint name="firsthost_5012">
<http uri-template="http://firsthost.com:5012{+uri.var.servicepath}"/>
</endpoint>
<endpoint name="firsthost_5022">
<http uri-template="http://firsthost.com:5022{+uri.var.servicepath}"/>
</endpoint>
</loadbalance>
<property xmlns:ns="http://org.apache.synapse/xsd"
name="uri.var.servicepath"
expression="get-property('To')"/>
</endpoint>
这里发生了很多神奇的事情 - 首先我们将上下文 uri 保存到一个名为 uri.var.servicepath 的特殊变量中,现在我们将使用它与 WSO 4.7.0 及更高版本提供的新“http 端点”功能。
http 端点使用 uri-template - 您可以在其中动态构建端点。所以我不必在配置中指定上下文 URI - 所以让我们说我们进入 ESB 的原始请求是这样的:
http://esbhost.com:8280/firstservice/10.06/service
这里的上下文 uri 是“/firstservice/10.06/service” - 所以我们希望将其附加到实际的应用层服务器 url。换句话说,我希望它变成http://firsthost.com:5022/firstservice/10.06/service
在 http 端点中,它允许我们使用我们之前定义的特殊变量 uri.var.servicepath。
<http uri-template="http://firsthost.com:5022{+uri.var.servicepath}"/>
由于 uri.var.servicepath 开头已经包含一个“/”,我没有单独指定。但请注意括号中的 + 号。那个有什么用?嗯——嗯,原来 WSO2 使用了有趣的第三方库——“该死的好 uri 处理器”——它主要用于 RESTful API。不幸的是,如果你明确地使用这样的字段, http: //firsthost.com :5022{uri.var.servicepath},第 3 方库会将上下文 uri 中存在的特殊字符转换为它们的 http 安全等效字符 - 例如 %20f 或其他。所以我们的 url 现在变成 http://firsthost:5022%20ffirstservice%20f10.06.... - 这不好。好吧,第三方库中的特殊功能可以节省一天的时间。如果您在特殊变量的开头加上 +,则此转换将关闭;) - 瞧 - 我们得到了我们想要的。
就是这样,伙计们。我将尝试在下面发布完整的配置(减去您可以在以上部分中找到的外部化条目)
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://ws.apache.org/ns/synapse">
<registry provider="org.wso2.carbon.mediation.registry.WSO2Registry">
<parameter name="cachableDuration">15000</parameter>
</registry>
<localEntry key="xslt-url-manipulator"
src="file:repository/myapp/resources/transform/url-in-wsdl-transform.xslt"/>
<localEntry key="local-enrty-firstservice-ep-key"
src="file:repository/myapp/resources/endpoint/firstservice-endpoints.xml">
</localEntry>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="routing_seq">
<in>
<log level="custom">
<property xmlns:ns="http://org.apache.synapse/xsd" name="context URI" expression="get-property('To')"/>
</log>
<conditionalRouter continueAfter="false">
<conditionalRoute breakRoute="false" asynchronous="false">
<condition>
<or>
<match type="url" regex="/firstService/10\.06/.*"/>
<match type="url" regex="/firstServiceVariant/.*"/>
</or>
</condition>
<target sequence="firstService_seq"/>
</conditionalRoute>
<conditionalRoute breakRoute="false" asynchronous="false">
<condition>
<match type="url" regex="/secondService.*"/>
</condition>
<target sequence="second_seq"/>
</conditionalRoute>
</conditionalRouter>
</in>
</sequence>
<sequence name="wsdl_transformer_seq">
<xslt xmlns:ns="http://org.apache.synapse/xsd"
key="xslt-url-manipulator"
source="/"/>
<send/>
</sequence>
<sequence name="fault">
<log level="full">
<property name="MESSAGE" value="Executing default 'fault' sequence"/>
<property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE" expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="firstservice_seq">
<in>
<property name="REST_URL_POSTFIX" scope="axis2" action="remove"/>
<switch xmlns:ns="http://org.apache.synapse/xsd" source="get-property('To')">
<case regex=".*(?:\?[Ww][Ss][Dd][Ll]|\.[Xx][Ss][Dd])\s*$">
<property name="HTTP_METHOD" value="GET"/>
<property name="messageType" value="text/xml"/>
<send receive="wsdl_transformer_seq">
<endpoint key="local-enrty-firstservice-ep-key"/>
</send>
<drop/>
</case>
<default>
<property name="HTTP_METHOD" value="POST"/>
<send>
<endpoint key="local-enrty-firstservice-ep-key"/>
</send>
</default>
</switch>
</in>
</sequence>
<sequence name="main">
<in>
<filter xmlns:ns="http://org.apache.synapse/xsd"
source="get-property('To')"
regex="http://localhost:9000.*">
<then>
<send/>
</then>
<else/>
</filter>
<sequence key="routing_seq"/>
</in>
<out>
<send/>
</out>
<description>The main sequence for the message mediation</description>
</sequence>
</definitions>
我知道这是一篇很长的帖子——但想为关心的人解释一下细节。希望它可以帮助某人。