包含流变量的条件

本页面适用于 ApigeeApigee Hybrid

查看 Apigee Edge 文档。

条件语句是所有编程语言中的常用控制结构。与编程语言一样,API 代理配置支持针对流、政策、步骤和 RouteRule 的条件语句。通过定义条件语句,可为 API 定义动态行为。此动态行为可让您执行一些操作,比如仅针对移动设备将 XML 转换为 JSON,或根据请求消息的内容类型或 HTTP 谓词路由到后端网址。

本主题介绍如何在运行时使用条件动态应用 API 管理功能,而无需编写任何代码。

配置条件语句

条件行为通过组合使用条件和变量在 API 代理中实现。使用 Condition 元素创建条件语句。以下是空条件:

<Condition></Condition>

如需创建条件语句,请使用以下语法添加条件运算符和变量:

<Condition>VARIABLE_NAME OPERATOR "VALUE"</Condition>

例如:

<Condition>request.verb = "GET"</Condition>

支持的条件运算符包括 =(等于)、!=(不等于)和 >(大于)。为方便阅读,您也可以将条件写成以下文本:equalsnotequalsgreaterthan

使用 URI 路径时,可以使用 ~/MatchesPath。还可以通过 ~~ 运算符匹配 JavaRegex 正则表达式。

条件用于定义到后端 API 资源的 API 代理条件流(请参阅创建到后端 API 资源的条件流)。如需查看条件的完整列表,请参阅条件参考

变量

条件通过求变量的值来完成工作。变量是由 API 代理或 API 代理配置本身的属性执行的 HTTP 事务的属性。每当 API 代理收到来自应用的请求时,Apigee 都会填充与系统时间、应用的网络信息、消息的 HTTP 标头、API 代理配置、政策执行等相关联的一个长长的变量列表。这会创建一个内容丰富的上下文,可供您用来设置条件语句。

变量始终使用虚线表示法。例如,请求消息上的 HTTP 标头将作为名为 request.header.HEADER_NAME 的变量提供。因此,为了评估 Content-type header,您可以使用变量 request.header.Content-type。例如,request.header.Content-type = "application/json" 表示请求的内容类型应为 JSON。

假设您需要创建一个条件语句,作用是使得仅当请求消息是 GET 时,系统才会强制执行某个政策。如需创建用于对请求的 HTTP 谓词求值的条件,请创建以下条件语句。此条件中的变量为 request.verb。此变量的值为 GET。运算符为 =

<Condition>request.verb = "GET"</Condition>

此外,您也可以使用:

<Condition>request.verb equals "GET"</Condition>

Apigee 会使用此类语句来对条件进行求值。如果与请求关联的 HTTP 谓词是 GET,则以上示例的求值结果为 GET。如果与请求关联的 HTTP 谓词是 POST,则语句的求值结果为 POST

如需启用动态行为,可以将条件附加到流、步骤和 RouteRule。

将条件附加到流时,将创建“条件流”。条件流仅在条件为 true 时执行。您可以根据需要将任意数量的政策附加到条件流中。借助条件流,您可为满足特定条件的请求或响应消息创建非常专业的处理规则。

例如,如需创建仅当请求谓词为 GET 时执行的流:

<Flows>
  <Flow name="ExecuteForGETs">
  <Condition>request.verb="GET"</Condition>
  </Flow>
</Flows>

要为 GET 请求创建一个流,并为 POST 请求创建另一个流,请执行以下操作:

<Flows>
  <Flow name="ExecuteForGETs">
    <Condition>request.verb="GET"</Condition>
  </Flow>
  <Flow name="ExecuteForPOSTs">
    <Condition>request.verb="POST"</Condition>
  </Flow>
</Flows>

如下例所示,您可以将条件应用于政策步骤本身。只有在满足请求消息为 POST 条件时,以下条件才会导致强制执行 VerifyApiKey 政策

<PreFlow name="PreFlow">
    <Request>
        <Step>
            <Condition>request.verb equals "POST"</Condition>
            <Name>VerifyApiKey</Name>
        </Step>
    </Request>
</PreFlow>

在定义此类条件流后,您就可以将政策附加到这些条件流,使 API 代理针对 GET 请求强制执行一组政策,为 POST 请求强制执行另一组政策。

如需了解全面的参考信息,请参阅以下资源:

示例 1

以下示例展示了在 ProxyEndpoint 响应流中配置的单个条件流 Convert-for-devices。将条件作为元素添加到条件应用于的实体。在此示例中,条件是流的一个组件。因此,只要语句的求值结果为 true,就会执行该流。

<Flows>
  <Flow name="Convert-for-devices">
  <Condition>(request.header.User-Agent = "Mozilla")</Condition>
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

对于从应用收到的每个请求,Apigee 将出现的所有 HTTP 标头的值存储为变量。如果请求包含名为 User-Agent 的 HTTP 标头,则该标头及其值将存储为名为 request.header.User-Agent 的变量。

根据上面的 ProxyEndpoint 配置,Apigee 会检查 request.header.User-Agent 变量的值以查看条件的求值结果是否为 true。

如果条件的求值结果为 true,即变量 request.header.User-Agent 的值等于 Mozilla,则会执行条件流,并强制执行名为 ConvertToJSONXMLtoJSON 政策。否则,系统不会执行该流,并会向发出请求的应用返回未经修改的 XML 响应(采用 XML 格式)。

示例 2

让我们用一个具体的示例进行说明。在该示例中,您需要将响应消息从 XML 转换为 JSON - 但仅适用于移动设备。首先,创建政策,用于将 Weather API 的 XML 格式的响应转换为 JSON:

<XMLToJSON name="ConvertToJSON">
  <Options>
  </Options>
  <OutputVariable>response</OutputVariable>
  <Source>response</Source>
</XMLToJSON>

上述政策配置会指示 API 代理获取响应消息,使用默认设置从 XML 转换为 JSON,然后将结果写入新的响应消息。(如果要将请求消息从 XML 转换为 JSON,则只需将这两个值都设置为 request 即可。)

因为您想要将响应从 XML 转换为 JSON,所以您需要配置条件响应流以执行转换。例如,如需将所有响应先从 XML 转换为 JSON 格式再返回给客户端应用,请配置以下 ProxyEndpoint 响应流。

<Flows>
  <Flow name="Convert-for-devices">
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

使用标准请求调用 API 时,响应将采用 JSON 格式。

不过,您的目标是仅当发出请求的客户端是移动设备时,才能将天气报告转换为 JSON 格式。如需实现此类动态行为,您必须向流添加条件语句。

测试条件流

在此示例请求中,HTTP User-Agent 标头设置为 Mozilla,使得条件语句的求值结果为 true 并执行条件流 Convert-for-devices

curl -H "User-Agent:Mozilla" http://example.com/weather/forecastrss?w=12797282

或者,当 Python 可用时进行整齐打印:

curl -H "User-Agent:Mozilla" http://example.com/weather/forecastrss?w=12797282 | python -mjson.tool

示例响应:

. . .

"yweather_forecast": [
   {
      "code": "11",
      "date": "12 Dec 2012",
      "day": "Wed",
      "high": "55",
      "low": "36",
      "text": "Showers"
    },
    {
      "code": "32",
      "date": "13 Dec 2012",
      "day": "Thu",
      "high": "56",
      "low": "38",
      "text": "Sunny"
    }
  ]
}

. . .

如果您提交的请求缺少 User-Agent 标头,或者其值不是 Mozilla,则会产生 XML 格式响应。

$ curl http://example.com/weather/forecastrss?w=12797282

系统会返回未经修改的 XML 响应。

示例响应:

<yweather:forecast day="Wed" date="12 Dec 2012" low="36" high="55" text="Showers" code="11" /> <yweather:forecast day="Thu" date="13 Dec 2012" low="38" high="56" text="Sunny" code="32" />

模式匹配

本部分介绍如何在 Apigee 流中使用与条件匹配的模式。

运算符

本部分介绍如何在条件语句中使用以下模式匹配运算符:

Matches

我们先看看 Matches~ 条件运算符。这两个运算符相同之处在于英语版本 Matches 会被视为可读性更高的选项。

摘要Matches 运算符可提供两种可能性。您可以逐字匹配字符串,也可以 * 执行通配符匹配。正如您的预期,通配符与零个或多个字符匹配。下面我们来看看具体操作方式。

以下 XML 展示了步骤条件。当条件的求值结果为 true 时,将会执行 SomePolicy 政策。在此示例中,我们测试了变量 proxy.pathsuffix,它是 Apigee 中的一个内置变量,用于存储请求的路径后缀。不过,请注意,您可以测试包含字符串的任何流变量的值。因此,在本示例中,如果传入请求的基本路径为 /animals,且请求为 /animals/cat,则路径后缀为字面量字符串 /cat

<PreFlow name="PreFlow">
  <Request>
    <Step>
      <Condition>(proxy.pathsuffix Matches "/cat")</Condition>
      <Name>SomePolicy</Name>
    </Step>
  </Request>
  <Response/>
</PreFlow>

问题:什么样的代理路径后缀会导致执行 SomePolicy?只有一个可能。

API 调用

GET http://example.com/matchtest/cat

该政策是否执行?是,因为代理路径后缀与 /cat 完全匹配。如果后缀为 /bat/dog/ 或任何其他值,该政策将不会执行。

现在,看看以下条件语句,我们在其中使用了通配符 *

<Condition>(proxy.pathsuffix Matches "/*at")</Condition>

API 调用

GET http://example.com/matchtest/cat

该政策是否执行?是,因为通配符与任何字符匹配,“"/cat”是匹配项。

API 调用

GET http://example.com/matchtest/bat

该政策是否执行?是,因为通配符匹配任何字符,"/bat" 是匹配项。

API 调用

GET http://example.com/matchtest/owl

该政策是否执行?当然不执行 - 虽然通配符与 o 匹配,但字母 wl 不匹配。

现在,将通配符移到后缀的末尾:

<Condition>(proxy.pathsuffix Matches "/cat*")</Condition>

API 调用

GET http://example.com/matchtest/cat

该政策是否执行?是,因为通配符与零个或多个任意字符匹配。

API 调用

GET http://example.com/matchtest/bat

该政策是否执行?否,/bat 不是匹配项。

API 调用

GET http://example.com/matchtest/cat123

该政策是否执行?是,通配符与零个或零个以上任意字符匹配,因此 123 会生成匹配项。

API 调用

GET http://example.com/matchtest/cat/bird/mouse

该政策是否执行?是,由于通配符与零个或零个以上任意字符匹配,因此 /bird/mouse 会生成匹配项。请注意,类似这样的表达式会让您陷入麻烦,因为它会匹配字面量字符后的所有内容!

问题:Matches 运算符是否区分大小写?

区分。假设您的条件如下:

<Condition>(proxy.pathsuffix Matches "/*At")</Condition>

API 调用

GET http://example.com/matchtest/cat

该政策是否执行?否,通配符可匹配任何字母(不区分大小写),但小写 aA 不匹配。

API 调用

GET http://example.com/matchtest/bAt

该政策是否执行?是,大小写匹配。

问题:如何使用 Matches 运算符将字符转义?

使用百分比 % 字符将保留字符转义。例如:

<Condition>(proxy.pathsuffix Matches "/c%*at")</Condition>

API 调用

GET http://example.com/matchtest/cat

该政策是否执行?否,Matches 运算符寻找的是字面量字符串 c*at

API 调用

GET http://example.com/matchtest/c*at

问题:政策是否执行?

是,虽然此路径有点异常,但是它匹配。

JavaRegex

您可以看到,Matches 运算符适用于简单的场景。但您可以使用另一个运算符(即 JavaRegex 或 ~~ 运算符)。这两个运算符是相同的,但 JavaRegex 可读性更好。它之所以称为 JavaRegex,是因为它允许正则表达式模式匹配,而 Apigee 遵循与 Java 语言中的 java.util.regex 包中的类相同的规则。JavaRegex 运算符的工作方式与 Matches 运算符大不相同,因此,务必不要混淆这两者!

摘要:通过 JavaRegex 运算符,您可以在条件语句中使用正则表达式语法。

以下代码显示了步骤条件。如果条件计算结果为 true,则执行 SomePolicy 政策。在此示例中,我们测试了变量 proxy.pathsuffix,它是 Apigee 中的一个内置变量,用于存储请求的路径后缀。如果传入请求的基本路径为 /animals,且请求为 /animals/cat,则路径后缀为字面量字符串 /cat

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix JavaRegex "/cat")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

问题:什么样的代理路径后缀会导致执行 SomePolicy?与 Matches 运算符一样,在此示例中,只有一个可能。

API 调用

GET http://example.com/matchtest/cat

该政策是否执行?是,因为代理路径后缀与 /cat 完全匹配。如果后缀为 /bat/dog 或任何其他值,该政策将不会执行。

现在,让我们使用 * 限定符创建一个正则表达式。此限定符与零个或零个以上前面的字符匹配。

<Condition>(proxy.pathsuffix JavaRegex "/c*t")</Condition>

API 调用

GET http://example.com/matchtest/cat

该政策是否执行?不执行!* 限定符与零个或零个以上前面字符(即 c)匹配。

API 调用

GET http://example.com/matchtest/ccccct

该政策是否执行?是,因为通配符与零个或零个以上前面的字符匹配。

接下来,我们使用 ? 限定符,它只会匹配前面的字符一次,或者根本不匹配。

<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>

API 调用

GET http://example.com/matchtest/cat

该政策是否执行?区分。? 限定符与零个或零个以上前面的字符(即 a)匹配。

API 调用

GET http://example.com/matchtest/ct

该政策是否执行?区分。? 限定符与一个前面的字符匹配,或者匹配。在此示例中,没有 a 字符,因此条件的计算结果为 true

API 调用

GET http://example.com/matchtest/caat

该政策是否执行?否。? 限定符与一个前面的字符(即 a)匹配。

接下来,我们使用正则表达式的 [abc]grouping 样式。它与字符 abc 匹配。

<Condition>(proxy.pathsuffix JavaRegex "/[cbr]at")</Condition>

API 调用

GET http://example.com/matchtest/cat

该政策是否执行?区分。我们在这里使用正则表达式,[cbr] 表达式与 cbr 匹配。这些调用也匹配:

GET http://example.com/matchtest/bat

GET http://example.com/matchtest/rat

但这不是一个匹配项:

GET http://example.com/matchtest/mat

问题:JavaRegex 运算符是否区分大小写?

区分。假设您的条件如下:

<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>

API 调用

GET http://example.com/matchtest/cat

该政策是否执行?是,正则表达式与零个或一个前面的字符(即 a)匹配。

API 调用

GET http://example.com/matchtest/cAt

问题:该政策是否执行?

否,因为大写字母 A 与小写 a 不匹配。

MatchesPath

还可以指定像 ~/ 这样的 MatchesPath 运算符。其类似于 Matches (~) 和 JavaRegex (~~) 运算符。但 MatchesPath 完全不同。

请记住,此运算符将路径视为一系列部分。因此,如果路径为 /animals/cats/wild,您可以将路径视为由 /animals/cats/wild 等部分组成。

MatchesPath 运算符允许您使用两个通配符表示法:单星号 (*) 和双星号 (**)。单星号与一个路径元素相匹配。双星号与一个或多个路径元素相匹配。

让我们看一个示例:在此示例中,我们测试了变量 proxy.pathsuffix,它是 Apigee 中的一个内置变量,用于存储请求的路径后缀。不过,请注意,您可以测试包含字符串的任何流变量的值。

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/*")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

问题:什么样的代理路径后缀会导致执行 SomePolicy?

API 调用

GET http://example.com/matchtest/animals

问题:该政策是否执行?

否,因为条件需要在 /animals 后面使用另一个路径元素,如通过 /* 指定的路径元素。

API 调用

GET http://example.com/matchtest/animals/

该政策是否执行?是,该路径还有另一个路径元素(/animals/ 后面的部分),但它是空的。

API 调用

GET http://example.com/matchtest/animals/cats

该政策是否执行?是,因为路径在 /animals 后面明确包含一个元素 (/cats)

API 调用

GET http://example.com/matchtest/animals/cats/wild

问题:该政策是否执行?

否,因为单个星号仅匹配一个路径元素,并且此 API 在 /animals 后面有多个元素。

现在我们使用双星号:

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/**")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

问题:什么样的代理路径后缀会导致执行 SomePolicy?

API 调用

GET http://example.com/matchtest/animals

该政策是否执行?否,因为条件需要至少一个由 /** 指定的以下路径元素。

API 调用

GET http://example.com/matchtest/animals/

该政策是否执行?

是,该路径还有另一个路径元素(/animals/ 后面的部分),但它是空的。

API 调用

GET http://example.com/matchtest/animals/cats

该政策是否执行?

是,因为路径中至少有一个元素在 /animals 后面

API 调用

GET http://example.com/matchtest/animals/cats/wild

该政策是否执行?

是,因为路径在 /animals 后面包含多个元素

混用星号

您可以使用单星号 (*) 和双星号 (**) 的组合,以进一步优化您的路径匹配。

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/*/wild/**")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

API 调用

所有这些 API 调用都会产生匹配项:

GET http://example.com/matchtest/animals/cats/wild/

GET http://example.com/matchtest/animals/dogs/wild/austrailian



GET http://example.com/matchtest/animals/birds/wild/american/finches

API 资源

RESTful 服务是 API 资源的集合。API 资源是一种 URI 路径片段,用于识别开发者可通过调用 API 访问的某个实体。例如,如果您的服务提供天气报告和天气预报,您的后端服务可能会定义两个 API 资源:

  • http://mygreatweatherforecast.com/reports
  • http://mygreatweatherforecast.com/forecasts

当您创建 API 代理(如构建您的第一个 API 代理中所示)时,您至少创建一个映射到后端服务的别名基础网址。例如:

后端基础网址 新的/等效 API 代理网址
http://mygreatweatherforecast.com http://example.com/mygreatweatherforecast

此时,您可以使用任一基础网址对后端进行 API 调用。但是,当您使用 API 代理网址时,内容会开始变得有趣。

除了 Apigee 在您使用 API 代理时开始收集的 API 分析之外,代理还可以定义映射到后端资源的条件流。实质上,如果针对 /reports 资源进行 GET 调用,Apigee 应执行某项操作。

下图显示了最终访问同一后端的两个网址之间的行为差异。一个是非代理资源网址,另一个是具有到同一后端资源的条件流的 Apigee API 代理。下面将详细介绍条件流。

对于具有条件流的 Apigee API 代理网址,响应会将 XML 转换为 JSON 并收集分析数据。

API 代理如何映射到特定的后端资源

通过将 API 代理网址映射到后端服务的基础网址(创建代理时),您可以向特定资源添加条件流,例如前面提到的 /reports/forecasts 资源。

假设针对 /reports/forecasts 资源进行调用时您希望 Apigee 执行某项操作。此时,您不是告诉 Apigee 执行什么操作,而是应该监听对这些资源的调用。您可以使用条件执行此操作。在 Apigee API 代理中,可为 /reports/forecasts 创建条件流。为了阐明概念,以下 API 代理 XML 展示了这些条件可能的样子。

<Flows>
    <Flow name="reports">
        <Description/>
        <Request/>
        <Response/>
        <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition>
    </Flow>
    <Flow name="forecasts">
        <Description/>
        <Request/>
        <Response/>
        <Condition>(proxy.pathsuffix MatchesPath "/forecasts") and (request.verb = "GET")</Condition>
    </Flow>
</Flows>

这些条件指定当网址中传入包含 /reports/forecastsGET 请求时,Apigee 执行您通过附加到流的政策执行您(API 开发者)告诉它执行的任何操作。

现在,我们通过示例告诉 Apigee 在满足条件时执行什么操作。在以下 API 代理 XML 中,当 GET 请求发送至 https://example.com/mygreatweatherforecast/reports 时,Apigee 会执行响应中的 XML-to-JSON-1 政策。

<Flows>
  <Flow name="reports">
    <Description/>
    <Request/>
    <Response>
      <Step>
        <Name>XML-to-JSON-1</Name>
      </Step>
    </Response>
  <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition>
</Flow>

除了这些可选的条件流之外,每个 API 代理还随附两个默认流:在条件流之前执行的 <PreFlow> 以及在条件流之后执行的 <PostFlow>。在对 API 代理进行任何调用时,这些条件流都有助于执行政策。例如,如果您要在每次调用时验证应用的 API 密钥,则无论访问哪个后端资源,您都可以对 <PreFlow> 添加 Verify API Key 政策。如需详细了解流,请参阅配置流

创建到后端资源的条件流

在 API 代理中,为后端资源定义条件流是可选操作。但是,通过这些条件流,您可以应用精细的管理和监控。

您将能够:

  • 以反映 API 模型语义的方式应用管理
  • 将政策和脚本化行为应用于个别资源路径 (URI)
  • 收集分析服务的精细指标

例如,假设您需要将不同类型的逻辑应用到后端 /developers/apps 资源。

为此,您需要在 API 代理中添加两个条件流:/developers/apps

新版代理编辑器

如需添加条件流,请执行以下操作:

  1. 选择代理编辑器中的开发标签页。
  2. 在左侧窗格中,选择代理端点 > 默认

    在左侧窗格中选择“代理端点”>“默认”。

  3. 点击响应窗格上方的 + 按钮。

    “添加条件流”按钮

  4. 添加条件流对话框中,输入以下配置:
    • 流名称Developers
    • 条件类型Path
    • 路径/developers

    “添加条件流”对话框。

    如果发送对 URI 末尾含有 /developers 的代理的调用,则会触发条件(并将执行政策)。

  5. 现在为 /apps 添加条件流,并假设您要对请求中的 URI 和 POST 动词触发条件。该配置涉及设置以下内容:
    • 流名称Apps
    • 条件类型Path and Verb
    • 路径/apps
    • 动词POST

    如果发送对 URI 末尾含有 /appsPOST 动词的代理的调用,则会触发条件(并将执行政策)。

添加的流显示在响应窗格中:

“添加条件流”对话框。

经典版代理编辑器

在 API 代理编辑器的导航器窗格的开发窗格中,点击代理端点中的默认值旁边的

当您将指针悬停在默认值旁边的加号上时,悬停文字会显示“添加新流”。

新建条件流窗口中,输入以下重要配置:

  • 流名称Developers
  • 条件类型Path
  • 路径/developers

在“新建条件流”窗口中,一个名为“Developers”的流使用以下说明进行了配置:“App developers registered with Developer Services”。

如果发送对 URI 末尾含有 /developers 的代理的调用,则会触发条件(并将执行政策)。

现在为 /apps 添加条件流,并假设您要对请求中的 URI 和 POST 动词触发条件。该配置涉及设置以下内容:

  • 流名称Apps
  • 条件类型Path and Verb
  • 路径/apps
  • 动词POST

在“新建条件流”窗格中,名为“Apps”的流使用以下说明进行了配置:“Developer apps registered in Developer Services.”。

如果发送对 URI 末尾含有 /appsPOST 动词的代理的调用,则会触发条件(并将执行政策)。

导航器窗格中,您会看到 AppsDevelopers 的新流。

Apps 和 Developers 的新流显示在“导航器”窗格中的“代理端点”下。

选择其中一个流以在 API 代理编辑器代码视图中查看条件流配置:

<Flow name="Apps">
    <Description>Developer apps registered in Developer Services</Description>
    <Request/>
    <Response/>
    <Condition>(proxy.pathsuffix MatchesPath "/apps") and (request.verb = "POST")</Condition>
</Flow>

如您所见,API 资源只是对入站请求的 URI 路径求值的条件流。(proxy.pathsuffix 变量识别请求的 URI,其跟在 ProxyEndpoint 配置中所配置的 BasePath 后面。)

您定义的每个 API 资源均由 API 代理中的条件流实现。(请参阅配置流。)

将 API 代理部署到测试环境后,以下请求:

http://example.com/PROXY_PATH/apps

将会导致条件的求值结果为 true,且将执行此流以及所有关联的政策。

以下示例条件使用 Java 正则表达式来识别对 /apps 资源(有或没有尾随斜杠:/apps/apps/**)的调用:

<Condition>(proxy.pathsuffix JavaRegex "/apps(/?)") and (request.verb = "POST")</Condition>

如需详细了解这种类型的条件,请参阅 Apigee 社区中的如何匹配,无论结尾是否有“/”...

为分层 URI 建模

在某些情况下,您会拥有分层 API 资源。例如,Developer apps list API 提供了一种方法,用于列出属于某个开发者的所有应用。URI 路径如下:

/developers/DEVELOPER_EMAIL/apps

您可能拥有这样的资源:可针对集合中的每个实体生成唯一 ID,集合有时按如下方式注释:

/genus/:id/species

此路径以同等方式应用于以下两个 URI:

/genus/18904/species
/genus/17908/species

如需在 API 资源中表示此结构,您可以使用通配符。例如:

/developers/*/apps
/developers/*example.com/apps
/genus/*/species

这些操作会将分层 URI 作为 API 资源进行适当解析。

在某些情况下,对于深度分层 API,您可能只想解析特定 URI 片段下的所有内容。为此,请在资源定义中使用双星号通配符。例如,如果您定义以下 API 资源:

/developers/**

该 API 资源将解析以下 URI 路径:

/developers/DEVELOPER_EMAIL/apps
/developers/DEVELOPER_EMAIL/keys
/developers/DEVELOPER_EMAIL/apps/APP_ID/keys

在 API 代理定义中,条件流条件如下所示:

<Condition>(proxy.pathsuffix MatchesPath "/developers/**") and (request.verb = "POST")</Condition>

更多示例

附加到 RouteRule 的条件

<RouteRule name="default">
  <!--this routing executes if the header indicates that this is an XML call. If true, the
    call is routed to the endpoint XMLTargetEndpoint-->
  <Condition>request.header.content-type = "text/xml"</Condition>
  <TargetEndpoint>XmlTargetEndpoint</TargetEndpoint>
</RouteRule>

附加到政策的条件

<Step>
  <!--the policy MaintenancePolicy only executes if the response status code is exactly 503 -->
  <Condition>response.status.code = 503</Condition>
  <Name>MaintenancePolicy</Name>
</Step>

条件流

<!-- this entire flow is executed only if the request verb is a GET-->
<Flow name="GetRequests">
  <Condition>request.verb="GET"</Condition>
  <Request>
    <Step>
<!-- this policy only executes if request path includes a term like statues-->
<Condition>request.path ~ "/statuses/**"</Condition>
      <Name>StatusesRequestPolicy</Name>
    </Step>
  </Request>
  <Response>
    <Step>
<!-- this condition has multiple expressions. The policy executes if the response code status is exactly 503 or 400-->
<Condition>(response.status.code = 503) or (response.status.code = 400)</Condition>
      <Name>MaintenancePolicy</Name>
    </Step>
  </Response>
</Flow>

条件中的示例运算符

以下是用于创建条件的运算符的一些示例:

  • request.header.content-type = text/xml
  • request.header.content-length < 4096 && request.verb = PUT
  • response.status.code = 404 || response.status.code = 500
  • request.uri MatchesPath /*/statuses/**
  • request.queryparam.q0 NotEquals 10

实例示例:忽略路径末尾的 /

Apigee 开发者通常希望处理以下两个路径后缀:/cat/cat/。这是因为某些用户或客户端可能会通过路径末尾的额外斜杠来调用您的 API,并且您必须能够在条件语句中进行处理。该确切用例讨论了如何匹配,无论结尾是否有“/”...

如果愿意,您可以在不使用 Regex 的情况下实现此目的,如下所示:

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix = "/cat") OR (proxy.pathsuffix = "/cat/")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

这是一个不错的方案。它清楚易懂。

但是,您可以使用正则表达式执行相同的操作,如下面的示例所示。括号用于对语句的正则表达式部分进行分组,但它们不是必需的。

<Condition>(proxy.pathsuffix JavaRegex "/cat(/?)"</Condition>

API 调用

GET http://example.com/matchtest/cat
or
GET http://example.com/matchtest/cat/

该政策是否执行?区分。请注意,在正则表达式中,? 字符表示:与零个或一个前面的字符匹配。因此,/cat/cat/ 都是匹配项。

API 调用:

GET http://example.com/matchtest/cat/spotted

该政策是否执行?否。正则表达式匹配零个或一个前面的字符,不允许任何其他字符。

使用 JavaRegex 匹配任意字符串

在本主题的所有示例中,我们演示了如何匹配一个内置流变量:proxy.pathsuffix。不妨了解一下,您可以对任意字符串或流变量进行模式匹配,无论它是否为内置代理变量(如 proxy.pathsuffix)。

例如,如果您的条件可以测试任意字符串,这些字符串可能是后端载荷中返回的字符串,或者是从身份验证服务器查找返回的字符串,则您可以使用匹配的运算符来测试它们。如果使用 JavaRegex,则正则表达式将与整个主题字符串进行比较。如果主题是 abc 并且正则表达式是 [a-z],则没有匹配项,因为 [a-z]一个 Alpha 字符完全匹配。表达式 [a-z]+ 的工作原理与 [a-z]*[a-z]{3} 相同。

我们来看一个具体的示例。假设身份验证服务器以英文逗号分隔的字符串形式返回角色列表:editor, author, guest

为了测试是否存在 editor 角色,该构造将不起作用,因为 editor 只是整个字符串的一部分。

<Condition>returned_roles ~~ "editor"</Condition>

不过,下面这个构造可以起作用:

<Condition>returned_roles ~~ ".*\beditor\b.*")</Condition>

它可以起作用的原因是它通过 .* 前缀和后缀,考虑了字词分开和字符串的任何其他部分。

在此示例中,您还可以使用 Matches 运算符测试 editor

<Condition>returned_roles ~~ "*editor*")</Condition>

但是,如果您需要更高的精度,JavaRegex 通常是更好的选择。

将 JavaRegex 表达式中的双引号转义

条件语法要求将 JavaRegex 表达式用双引号引起来;因此,如果您有一个包含英文双引号的正则表达式,则需要采用备用方法来匹配它们。这种方法是 Unicode。例如,假设您传入一个包含双引号的标头,如下所示:

 -H 'content-type:multipart/related; type="application/xop+xml"'

如果您尝试在正则表达式条件中匹配该标头,则会收到 Invalid Condition 错误,因为表达式包含双引号:

request.header.Content-Type ~~ "(multipart\/related)(; *type="application\/xop\+xml\")"

解决方法是将基于 ASCII 的双引号替换为对应的 Unicode 等效项 \u0022。例如,以下表达式有效,会产生预期的结果:

request.header.Content-Type ~~ "(multipart\/related)(; *type=\u0022application\/xop\+xml\u0022)"