wso2 esb customURI / serviceURI with expression

时间:2013-07-22 16:11:43

标签: wso2 esb wso2esb

我正在尝试实施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包含到代理将请求发送到的最终端点。请注意,端点将是条目列表(负载平衡条目),但为了简单起见,我只保留了一个端点条目。

2 个答案:

答案 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>

我知道这是一篇非常冗长的帖子 - 但是想要为那些关心的人解释细节。 希望它可以帮到某人。