参数与条件表达式的使用

本文讲述API网关的参数以及条件表达式的使用。

1. 概述

在插件中,支持用户从当前的请求应答系统上下文中获取参数,并使用自定义的条件表达式对参数进行判断,本文描述参数的定义方法与条件表达式的书写方法。

2. 参数的定义

2.1. 定义方式

在使用条件表达式前,需要先在parameters字段中将所有需要在条件表达式中需要使用的参数进行显式定义,参考下面的例子:

---
parameters:
  method: "Method"
  appId: "System:CaAppId"
  action: "Query:action"
  userId: "Token:UserId"

parameters字段类型是字符串类型的键值对,keyvalue的定义规范为

  • key 表示在条件表达式中使用的变量名,变量名的规则为[a-zA-Z_][a-zA-Z0-9]+, 唯一

  • value 表示参数所在的位置,使用{location}{location}:{name}的方式进行定义,请参考如下的例子:

    • location 表示参数所在的位置,参考下一节的详细描述

    • name 表示参数的名称,用于在所在位置中定位参数,比如Query:q1表示请求的QueryString中名字为q1的第一个值

2.1. 参数的支持位置

在使用条件表达式前,我们需要先定义参与条件表达式计算的参数,目前API网关支持在插件中直接使用如下位置的参数

位置名称

适用范围

说明

Method

请求

HTTP请求方法(大写),如:

GET , POST

Path

请求

HTTP完整请求路径,如:

/path/to/query

StatusCode

应答

后端的HTTP应答码,如:

200 , 400

ErrorCode

应答

API网关系统错误码

Header

请求/应答

使用 Header:{Name} 获取名字为

{Name} 的HTTP头的第一个值

Query

请求

使用 Query:{Name} 获取QueryString中名字为 {Name} 的第一个值

Form

请求

使用 Form:{Name} 获取请求Form中名字为 {Name} 的第一个值

Host

请求

使用 Host:{Name} 获取匹配到的泛域名模板参数

Parameter

请求

使用 Parameter:{Name} 获取用户API自定义参数中名字为 Name 的第一个值

BodyJsonField

应答*

使用BodyJson:{JPath}JSONPath 方式获取请求/应答包体中的JSON字段值

System

请求/应答

使用 System:{Name} 获取名字为{Name} 的系统参数值

Token

请求/应答

当处于jwt插件认证时,使用Token:{Name} 获取token中名字为 {Name} 的值

XFF

请求

填写格式为XFF:{index},index的值为X-Forwarded-For头中IP排序序号,从0开始算,允许负数,比如X-Forwarded-For的值为IP1,IP2,IP3,那么如果index值为0,取IP1,如果index的值为-1,取IP3,也就是倒数第一个IP

取值规则的说明

  • 参数访问控制插件,流量控制插件,后端路由插件发生在请求阶段,插件仅支持适用范围为请求的参数位置:Method,Path,Header,Query,Form,Parameter,System,Token,XFF

  • 错误码映射插件发生在应答阶段,插件仅支持适用范围为应答的参数位置:StatusCode,ErrorCode,Header,BodyJsonField,System,Token

  • Method,Path,StatusCode,ErrorCodeXFF这几个位置仅提供Location即可,不需要Name

  • Header位置的参数,当用于请求阶段的插件时,读取来自客户端请求中的Header; 当用于应答阶段的插件时,读取来自后端应答中的Header

  • Parameter位置的参数,仅用于请求阶段的插件,查找API定义中同名的参数,使用参数名而非后端参数名查找,当参数不存在时返回为null

  • Host位置的参数,仅支持在泛域名参数提取,参考使用自定义域名调用API文档的3.2章节, 完整的Host请使用System:CaDomain读取系统参数

  • Path返回为完整的请求路径,如果需要Path位置的参数,请使用Parameter位置的参数

  • BodyJsonField位置的参数,目前仅支持在错误码映射插件中使用,使用JSONPath方式读取应答JSON包体的值,参考2.4. JSONPath使用说明

  • Token当配置了JWT认证插件时,使用Token:{CliamName}可以读取在插件定义的值,参考对应插件的文档

2.3. JSONPath使用说明

用于BodyJsonField位置,目前仅用于错误码映射插件,用于从后端返回的json包体中提取json中的字段,关于JSONPath的详细规范说明,请参考JSONPath介绍文档。

  • 例子:使用 code:"BodyJsonField:$.result_code" 可以从如下的包体中得到 result_code 的值,对于如下的包体,可以解析到 code : ok

{ "result_code": "ok", "message": ... }

2.4. 系统参数列表

参数名称

参数含义

取值列表

CaClientIp

请求来源客户端IP

如: 37.78.XX.XX ,fe80::1849:59fd:993c:fcff

CaDomain

请求的完整域名(Host头)

如:

example.aliyundoc.com

CaAppId

请求的 APP 的 ID

如:

49382332

CaAppKey*

请求的 APP 的 Key

如:

12983883923

CaRequestId

网关生成的唯一请求ID

如:

CCE4DEE6-26EF-46CB-B5EB-327A9FE20ED1

CaApiName

API 名称

如:

TestAPI

CaHttpSchema

调用协议

取值范围:http, https, ws

CaClientUa

客户端的UserAgent头

透传客户端上传的值

CaCloudMarketInstanceId

云市场购买关系ID

云市场

CaMarketExpriencePlan

是否开通云市场体验计划

开通:true

未开通:false

3. 条件表达式

条件表达式可在插件或其他场景中使用,用于在需要的场景中执行灵活的条件判断

3.1. 基本语法

  • 条件表达式与SQL表达式类似,比如:$A > 100 and '$B = 'B'

  • 表达式的基本为{参数} {操作符} {参数}格式,如:$A > 100参数支持变量参数常量参数

  • 变量参数$开头,用于引用在上下文中定义好的参数,例如:parameters中定义了q1:"Query:q1"的参数,在表达式中可以使用变量$q1,这个变量的值为当前请求中名为q1的Query参数的值

  • 常量参数支持字符串数字布尔类型,如"Hello",'foo',100,-1,0.1,true,请参考3.2. 参数类型与判断规则

  • 支持以下操作符

  • =, ==:等于判断

  • <>, !=:不等于判断

  • >, >=, <, <=:比较判断

  • like, !like:相似判断,在字符串头尾的%可用于判断字符串相似,如$Query like 'Prefix%'

  • in_cidr, !in_cidr:判断IP地址的掩码,例如:$ClientIp in_cidr '47.89.XX.XX/24'

  • 可使用null来判断参数是否为空,如:$A == null$A != null

  • 可以使用and, or, xor来组合连接不同的表达式,默认连接顺序为从右到左

  • 可以用小括号()来指定条件的优先级

  • 使用!(, )可以对括起来的表达式执行取反操作,如:!(1=1)结果为false

  • 系统内置了一些函数,用于一些特殊场景的判断

    • Random(): 产生一个0-1的浮点类型参数,用于蓝绿发布等一些需要随机的场合

    • Timestamp():返回以毫秒计数的Unix时间戳

    • TimeOfDay():按GMT时区,返回当前时间到当日零点的毫秒数

3.2. 参数类型与判断规则

  • 表达式中支持以下类型

    • STRING:字符串类型,支持单引号或双引号,如:"Hello", 'Hello'

    • NUMBER:整数或浮点数类型,如:1001-1, 0.1, -100.0

    • BOOLEAN:布尔类型,如:truefalse

  • 对于等于,不等于,比较操作符,不同类型的判断依据为:

    • STRING:使用字符串顺序执行判断,例如:

      • '123' > '1000' 结果为true

      • 'A123' > 'A120' 结果为true

      • '' < 'a' 结果为true

    • NUMBER:使用数字大小进行判断

      • 123 > 1000 结果为false

      • 100.0 == 100 结果为true

    • BOOLEAN:布尔值的判断依据为:true大于false

      • true == true 结果为true

      • false == false 结果为true

      • true > false 结果为true

  • 对于等于,不等于,比较操作符,如果左右两侧的参数类型不一致,参考以下的判断依据:

    • STRING NUMBER: 如果左值能转换为NUMBER类型,则按照数字大小判断,否则按照字符串大小判断,例如:

      • '100' = 100.0 结果为true

      • '-100' > 0 结果为false

    • STRING BOOLEAN: 当左值能够转换为BOOLEAN类型时(忽略大小写等于truefalse),按照BOOLEAN类型判断,否则除了!=判断外,其余的判断结果均为false,参考如下例子:

      • 'True' = true 结果为true

      • 'False' = false 结果为true

      • 'bad' = false 结果为false

      • 'bad' != false 结果为true,对于左值非truefalse的场景,除了!=操作符结果为true,其余结果均为false

      • 'bad' != true 结果为true

      • '0' > false 结果为false

      • '0' <= false 结果为false

    • NUMBERBOOLEAN: 永远返回false

  • null值可用于字段是否为空的判断,对于等于,不等于,比较操作符,判断依据为

    • 当参数$A为空时,$A == null 结果为true,$A != null 结果为false

    • 空字符串''不等于null时: '' == null 结果为false'' == ''结果为true

    • 当用于比较操作符时,任意一测值为null,则结果为false

  • like!like操作符,可用于字符串前缀、后缀、包含的判断,判断依据为

    • 表达式仅支持右值为STRING常量的写法,如$Path like '/users/%'

    • 右值两端的'%'字符可用于支持前缀、后缀、与包含判断,如

      • 前缀判断 $Path like '/users/%', $Path !like '/admin/%'

      • 后缀判断 $q1 like '%search', $q1 !like '%.do',

      • 包含判断 $ErrorCode like '%400%', $ErrorCode !like '%200%',

    • 当左值为非NUMBERBOOLEAN类型时,会转换为STRING格式后执行判断

    • 当左值为空值null时,结果为false

  • in_cidr!in_cidr表达式,可用于IP地址段掩码的判断,判断依据为

    • 表达式仅支持右值为STRING常量且符合IPv4或IPv6 CIDR格式的写法,如:

      • $ClientIP in_cidr '10.0.0.0/8'

      • $ClientIP !in_cidr '0:0:0:0:0:FFFF::/96'

    • 当左值类型为STRING类型时,会作为IPv4地址后进行判断

    • 当左值类型为NUMBER,BOOLEAN或为空时,结果为false

    • System:CaClientIp参数会返回客户端的IP地址,一般使用这种方式执行判断

4. 使用案例

  • 随机5%的几率:

Random() < 0.05
  • 判断当前API请求的是测试环境:

parameters:
  stage: "System:CaStage"
$CaStage = 'TEST'
  • 自定义参数中的UserName是Admin且来源IP在47.47.XX.XX/24范围内

parameters:
  UserName: "Token:UserName"
  ClientIp: "System:CaClientIp"
$UserName = 'Admin' and $CaClientIp in_cidr '47.47.XX.XX/24'
  • 当前请求的用户ID是1001,1098,2011中的一个,且使用HTTPS协议请求

parameters:
  CaAppId: "System:CaAppId"
  HttpSchema: "System:CaHttpSchema"
$CaHttpScheme = 'HTTPS' and ($CaAppId = 1001 or $CaAppId = 1098 or $CaAppId = 2011)`
  • 当应答StatusCode=200,包体json包体存在result_code且不为ok

parameters:
  StatusCode: "StatusCode"
  ResultCode: "BodyJsonField:$.result_code"
$StatusCode = 200 and ($ResultCode <> null and $ResultCode <> 'ok')

5. 使用限制

  • 单个插件中的参数定义个数不超过16

  • 单个表达式的字符数不超过512个字符

  • BodyJsonField对请求或应答包体的限制为16K Bytes, 超过限制后将不会生效