全部产品
云市场

参数与条件表达式的使用

更新时间:2020-03-02 14:55:34

1. 概述

授权控制, 流量控制, 后端路由错误码映射 插件中,支持用户从当前的请求应答系统上下文中获取参数,并使用自定义的条件表达式对参数进行判断,本文描述参数的定义方法与条件表达式的书写方法。

2. 参数的定义

2.1. 定义方式

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

  1. ---
  2. parameters:
  3. method: "Method"
  4. appId: "System:CaAppId"
  5. action: "Query:action"
  6. 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,oauth2授权场景时,使用Token:{Name}获取token中名字为{Name}的值

取值规则的说明

  • 插件访问控制,流量控制,后端路由发生在请求阶段,插件仅支持适用范围为请求的参数位置:Method,Path,Header,Query,Form,Parameter,System,Token
  • 插件错误码映射发生在应答阶段,插件仅支持适用范围为应答的参数位置: StatusCode,ErrorCode,Header,BodyJsonField,System,Token
  • Method,Path,StatusCode,ErrorCode 这几个位置仅提供Location即可, 不需要Name
  • Header位置的参数,当用于请求阶段的插件时,读取来自客户端请求中的Header; 当用于应答阶段的插件时,读取来自后端应答中的Header
  • Parameter位置的参数,仅用于请求阶段的插件,查找API定义中同名的参数,使用参数名而非后端参数名查找,当参数不存在时返回为null
  • Host位置的参数,仅支持在泛域名参数提取,参考泛域名使用说明, 完整的Host请使用System:CaDomain读取系统参数
  • Path返回为完整的请求路径,如果需要Path位置的参数,请使用Parameter位置的参数
  • BodyJsonField位置的参数,目前仅支持在错误码映射中使用,使用JSONPath方式读取应答json包体的值,参考2.4. JSONPath使用说明
  • Token当配置了JWT授权OAuth2插件时, 使用Token:{CliamName}可以读取在插件定义的值,参考对应插件的文档

2.3. JSONPath使用说明

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

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

2.4. 系统参数列表

参数名称 参数含义 取值列表
CaClientIp 请求来源客户端IP 如: 37.78.3.3, fe80::1849:59fd:993c:fcff
CaDomain 请求的完整域名(Host头) 如: api.foo.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.0.0/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
    • NUMBER BOOLEAN: 永远返回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%的几率为真:
  1. Random() < 0.05
  • 判断当前API请求的是测试环境:
  1. parameters:
  2. stage: "System:CaStage"
  1. $CaStage = 'TEST'
  • 自定义参数中的UserName是Admin且来源IP在47.47.74.0/24范围内
  1. parameters:
  2. UserName: "Token:UserName"
  3. ClientIp: "System:CaClientIp"
  1. $UserName = 'Admin' and $CaClientIp in_cidr '47.47.74.0/24'
  • 当前请求的用户Id是1001,1098,2011中的一个,且使用HTTPS协议请求
  1. parameters:
  2. CaAppId: "System:CaAppId"
  3. HttpSchema: "System:CaHttpSchema"
  1. $CaHttpScheme = 'HTTPS' and ($CaAppId = 1001 or $CaAppId = 1098 or $CaAppId = 2011)`
  • 当应答StatusCode=200,包体json包体存在result_code且不为ok
  1. parameters:
  2. StatusCode: "StatusCode"
  3. ResultCode: "BodyJsonField:$.result_code"
  1. $StatusCode = 200 and ($ResultCode <> null and $ResultCode <> 'ok')

5. 使用限制

  • 单个插件中的参数定义个数不超过16
  • 单个表达式的字符数不超过512个字符
  • BodyJsonField对请求或应答应答包体的限制为16K Bytes, 超过限制后将不会生效