通用表达式语言 (CEL) 是一种开源的非图灵完备语言,可实现用于表达式求值的通用语义。服务扩展程序使用 CEL 条件的子集,根据属性数据做出链式评估决策。通常,条件表达式由一个或多个使用逻辑运算符(&&、|| 或 !)联接的语句组成。
属性
对于任何给定的连接请求,代理都会提取属性,这些属性是一组上下文信息。属性具有固定的类型(例如 string 或 int),并且可能会根据上下文而存在或不存在。
在处理匹配条件期间,属性会公开给 CEL 运行时。
无法将属性发送到扩展服务。
请求属性
您可以从请求中提取以下属性:
| 属性 | 属性类型 | 说明 |
|---|---|---|
request.headers |
map{string,string} | HTTP 请求标头的字符串到字符串映射。如果某个标头包含多个值,此映射中的值将是标头的所有值的英文逗号分隔字符串。此映射中的键均为小写。 |
request.method |
字符串 | HTTP 请求方法,例如 GET 或 POST。 |
request.host |
字符串 | 相当于 request.headers['host'] 的简便方法。
|
request.path |
字符串 | 所请求的 HTTP 网址路径。 |
request.query |
字符串 | HTTP 网址查询,格式为 未执行解码。 |
request.scheme |
字符串 | HTTP 网址 scheme,例如 HTTP 或 HTTPS。此属性的值均为小写。 |
request.backend_service_name |
字符串 | 向其转发请求的后端服务。 不适用于边缘扩展服务。 |
request.backend_service_project_number |
整数 | 使用共享 VPC 时,向其转发请求的后端服务的项目编号。 不适用于边缘扩展服务。 |
连接特性
您可以从连接中提取以下属性:
| 属性 | 属性类型 | 说明 |
|---|---|---|
source.ip |
字符串 | 请求的源 IP 地址。 |
source.port |
整数 | 下游客户端的连接端口。 |
connection.sni |
字符串 | 下行 TLS 连接中所请求的服务器名称。 |
connection.tls_version |
字符串 | 下行 TLS 连接的 TLS 版本。有效值:TLSv1、TLSv1.1、TLSv1.2 和 TLSv1.3。
|
connection.sha256_peer_certificate_digest |
字符串 | 下行 TLS 连接中对等证书的十六进制编码 SHA256 哈希(如果存在)。 |
运算符
服务扩展程序支持多种运算符,您可以使用这些运算符通过简单的表达式语句构建复杂的匹配条件。Service Extensions 支持逻辑运算符(例如 &&、|| 和 !)和字符串操作运算符(例如 x.contains('y'))。
字符串处理运算符用于匹配您定义的字符串或子字符串。例如,如果 HTTP 请求是向以 example.com 结尾的网域发出的,则 request.host.endsWith('.example.com') 的计算结果为 true。
借助逻辑运算符,您可以在条件表达式中验证多个变量。例如,request.method == 'GET' && request.host.matches('.example.com') 连接了两个语句,并且要求这两个语句均为 true,才能生成总体结果 true。
逻辑运算符
下表介绍了服务扩展程序支持的逻辑运算符。
| 示例表达式 | 说明 |
|---|---|
x == "foo" |
如果 x 等于常量字符串字面量实参,则返回 true。 |
x == R"fo'o" |
如果 x 等于不解释转义序列的指定原始字符串字面量,则返回 true。原始字符串字面量便于表示代码必须使用转义序列字符的字符串。 |
x == y |
如果 x 等于 y,则返回 true。 |
x != y |
如果 x 不等于 y,则返回 true。 |
x && y |
如果 x 和 y 均为 true,则返回 true。 |
x || y |
如果 x、y 或两者均为 true,则返回 true。 |
!x |
如果布尔值 x 为 false,则返回 true;如果布尔值 x 为 true,则返回 false。 |
m['k'] |
如果存在键 k,则返回字符串到字符串映射 m 中键 k 处的值。如果不存在键 k,则返回一个错误,导致正在评估的规则不匹配。 |
字符串操作运算符
下表介绍了服务扩展程序支持的字符串操作运算符。
| 表达式 | 说明 |
|---|---|
x.contains(y) |
如果字符串 x 包含子字符串 y,则返回 true。 |
x.startsWith(y) |
如果字符串 x 以子字符串 y 开头,则返回 true。 |
x.endsWith(y) |
如果字符串 x 以子字符串 y 结尾,则返回 true。 |
x.matches(y) |
如果字符串 服务扩展程序在编译 RE2 模式时使用 RE2::Latin1 选项,该选项会停用 Unicode 功能。 边缘扩展功能允许您在每个 CEL 表达式中仅使用一个正则表达式。 |
x.lower() |
返回字符串 x 的小写值。 |
x.upper() |
返回字符串 x 的大写值。 |
int(x) |
将字符串结果 x 转换为 int 类型。您可以使用标准算术运算符(例如大于 [>] 和小于等于 [≤])对转换后的字符串进行整数比较。这仅适用于可以为整数的值。 |
示例表达式
匹配发送给主机 example.com 并将 123 中的后端服务 bs1 作为最终目的地的所有请求:
request.host == "example.com" && request.backend_service_name == "bs1" && request.backend_service_project_number == 123
匹配路径为 */inventory 且包含 HTTP 标头 Hello 的所有请求:
request.path.endsWith("/inventory") && request.headers["Hello"] != ""
限制
为服务扩展指定 CEL 表达式时,存在以下限制:
- 每个扩展程序的表达式数量上限:边缘扩展程序为 1 个,其他扩展程序为 5 个
- 每个正则表达式的字符数上限:100
- 每个 CEL 表达式的字符数上限:500