0

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

4

2 回答 2

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 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 用于我的问题中的用例时,您会想到(至少我是这样)。

希望它可以帮助某人。正如我之前所说,如果我犯了任何错误或有更好的方法,请纠正我。

于 2013-07-23T22:00:47.387 回答
1

我找到了一个更清洁/更好的解决方案 - 它只是上述答案的增强版本。

主要挑战是让 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>

我知道这是一篇很长的帖子——但想为关心的人解释一下细节。希望它可以帮助某人。

于 2013-07-30T15:09:14.980 回答