我正在尝试实施ESB解决方案来替换复杂Web服务架构的Web层部分。 Web层只接收来自客户端的请求并分发给一组给定的应用层实例。
由于端点已经被客户端定义和使用,我必须使用这里描述的“CustomURI”方法构建ESB代理 - http://achala11.blogspot.com/2012/08/access-wsdl-for-customuri-wso2-esb.html - 以公开端点和wsdl。
请注意,ServiceURI仅允许指定固定的上下文路径(如果我错了,请更正我)。例如: 如果WSDL端点是http:// localhost:8280 / CustomURL / Part1 / Part2?wsdl,则相应的ServiceURI条目是
<parameter name="ServiceURI">/CustomURL/Part1/Part2</parameter>
我想要使用的是这样的表达式:
<parameter name="ServiceURI">/CustomURL/*</parameter>
表示代理将处理在上下文路径中以/ CustomURL开头的所有请求。在代理内部,我喜欢将上下文URI传播到发送块中定义的端点。我认为我发现了一种RESTful方式(完全不能让它完全工作)做我想做的事情。如您所见,我可以在api中指定上下文,然后使用resource的url-mapping选项将所有请求路由到api块。后来我尝试使用“http端点”方法构造端点,并附加了contextURI。
<api xmlns="http://ws.apache.org/ns/synapse" name="customService1" context="/CustomServices">
<resource methods="POST" url-mapping="/*">
<inSequence>
<log level="custom">
<property name="uri.var.servicepath" expression="get-property('To')"/>
</log>
<send>
<endpoint name="HTTPEndpoint">
<http method="POST" uri-template="http://localhost:8001/{uri.var.servicepath}"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<send/>
</outSequence>
</resource>
</api>
我希望您可以帮助我使用类似的SOAP服务解决方案 - 一种指定contextURI的方法,然后将contextURI包含到代理将请求发送到的最终端点。请注意,端点将是条目列表(负载平衡条目),但为了简单起见,我只保留了一个端点条目。
答案 0 :(得分:1)
我是WSO2 esb的新手,如果你发现任何错误,请纠正我。
用例: 看看这个 - http://achala11.blogspot.com/2012/08/access-wsdl-for-customuri-wso2-esb.html。它显示了一种在WSO2中允许SOAP服务的自定义wsdl URL的方法。嗯,就我而言,服务已经到位并被客户消费。因此,我无法使用WSO2中的“生成的”wsdl端点,并且必须确保现有的wsdl和服务URL将通过WSO2工作。请注意,我在这里处理SOAP,并且有很多RESTful服务的示例(包括用于处理端点操作的REST_URL_POSTFIX)。
您需要的关键信息是WSO2中有两个序列,所有请求都经过 - 即“主”和“故障”(故障仅在出现故障情况时使用)。 正如我在原始问题中所解释的那样,让代理服务做我想做的事情变得非常具有挑战性。代理服务在向端点传播上下文或为ServiceURI变量指定表达式方面提供的内容不多。然后我查看了“主要”序列条目,如上面发布的链接中所述。 WSO2团队正在做的只是使用正则表达式来检测传入上下文,如果它有“wsdl”,它们将请求路由到固定的wsdl端点并进一步停止流。好吧,我认为我们不必将代码保留在主序列中。 序列可以链接。这意味着你可以从main调用另一个序列,你可以做很多魔术(我不想在主序列中加入很多逻辑 - 我的c / c ++ / java经验可能会阻止我: )) - 如果您熟悉编程,则序列就像方法/函数调用。 Main是入口点,然后你可以调用你想要的任何方法,并从中做出更多的链接序列等。)
首先是主序列(不需要过滤器 - 基本上,。
<sequence name="main">
<in>
<log level="full"/>
<sequence key="ISP_seq"/>
</in>
<out>
<send/>
</out>
<description>The main sequence for the message mediation</description>
</sequence>
现在ISP_seq根据上下文路由请求(注意使用的正则表达式)。
<sequence xmlns="http://ws.apache.org/ns/synapse" name="ISP_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中,您将收到所有具有上下文URI的请求 - /firstService/10.06/(后跟任何内容 - 包括?wsdl :))或/ firstServiceVariant /(后跟任何内容)。
<match type="url" regex="/firstService/10\.06/.*"/>
<match type="url" regex="/firstServiceVariant/.*"/>
好的 - 现在转到将要处理firstService和其他服务的Sequence。
<sequence xmlns="http://ws.apache.org/ns/synapse" name="firstService_seq">
<in>
<!-- FIRST let us handle the WSDL requests. -->
<property name="REST_URL_POSTFIX" action="remove" scope="axis2"/>
<switch xmlns:ns="http://org.apache.synapse/xsd" source="get-property('To')">
<case regex="/firstService/10\.06/service\?[Ww][Ss][Dd][Ll]">
<send>
<endpoint>
<address uri="http://myappServer:10011/firstService10.06?wsdl" format="get"/>
</endpoint>
</send>
</case>
</switch>
<send>
<!-- below here, we will handle the actual SOAP requests -->
<endpoint>
<loadbalance algorithm="org.apache.synapse.endpoints.algorithms.RoundRobin">
<endpoint name="firstFarm_7011">
<address uri="http://hostA:7011/firstService/10.06/service"/>
</endpoint>
<endpoint name="firstFarm_7021">
<address uri="http://hostA:7021/firstService/10.06/service"/>
</endpoint>
<endpoint name="secondFarm_7011">
<address uri="http://hostX:7011/firstService/10.06/service"/>
</endpoint>
</loadbalance>
</endpoint>
</send>
</in>
<out>
<send/>
</out>
</sequence>
对不起,我很抱歉。不知何故,我无法从现有文档中弄清楚这一点。我希望通过代理服务提供相同的功能,以及当您考虑在我的问题中使用ESB作为用例时,您会想到(至少我是)。
希望它有所帮助。正如我先前所说,如果我犯了任何错误或者有更好的方法,请纠正我。
答案 1 :(得分:1)
我找到了一个更清洁/更好的解决方案 - 它只是上述答案的增强版本。
主要挑战是让SOAP WSDL和服务端点(Context URI)工作,而不像代理服务方法那样强制它。 请注意,如果您可以使用contextURI WSO2团队建议(/ 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 * 强>
现在我们已准备好处理传入的请求 - 请注意,我们已将应用程序识别为&#34; firstservice&#34;在上一步中。您可以在此处接收两种请求 - 一种是WSDL,另一种是soap请求
<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,以避免在app层中出现任何混淆,否则,可能会有一些垃圾SOAP主体部分从流中的某处注入。)
所以基本上,我们检查“To&#39;包含/firstservice/10.06/service?WSDL(如果是WSDL请求)或/firstservice/10.06/service等上下文URI的属性 - 如果它是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 reqeusts的特殊序列。在 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条目一样。所以我只会发布actul外部文件的内容。
这是一个艰难的cookie,我不得不深入研究WSO2的源代码,并找出一些&#34;无证的&#34;特征。嗯,这是&#34;没有记录&#34;在WSO2世界中,但是另外记录为WSO2使用第三方库,该库具有许多未在WSO2中发布的功能。 请注意,端点指向应用层实例,我们使用roundrobin算法将流量分配到可用的应用层实例。
<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的特殊变量中 现在我们将使用新的&#34; http端点&#34;功能可从WSO 4.7.0开始提供。
http端点使用uri-template - 您可以在其中动态构建端点。所以我不必在配置中指定上下文URI - 因此,让我们说我们进入ESB的原始请求是这样的:
http://esbhost.com:8280/firstservice/10.06/service
这里的上下文是&#34; /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已包含&#39; /&#39;在开始时,我没有单独指定。但请注意括号中的+号。那个有什么用?嗯 - 事实证明,WSO2使用了有趣的第三方库 - &#34;该死的好uri处理器&#34; - 它主要用于RESTful API。不幸的是,如果你清楚地使用这样的字段,http://firsthost.com:5022 {uri.var.servicepath},第三方库会将上下文uri中存在的特殊字符转换为它们的http安全等价物 - 类似于%20f或者其他。所以我们的网址现在变成了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>
我知道这是一篇非常冗长的帖子 - 但是想要为那些关心的人解释细节。 希望它可以帮到某人。