全部产品

参数与条件表达式的使用

更新时间:2020-08-26 18:06:58

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

,

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

{ "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%的几率为真:
Random() < 0.05
  • 判断当前API请求的是测试环境:
parameters:
  stage: "System:CaStage"
$CaStage = 'TEST'
  • 自定义参数中的UserName是Admin且来源IP在47.47.74.0/24范围内
parameters:
  UserName: "Token:UserName"
  ClientIp: "System:CaClientIp"
$UserName = 'Admin' and $CaClientIp in_cidr '47.47.74.0/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, 超过限制后将不会生效