条件式禁用全局插件
全局插件默认应用于所有路由,这对于强制执行组织级策略非常有用,例如日志记录、改写或流量控制。不过 ,有些路由可能需要从某些全局插件中豁免。
本指南将介绍如何使用路由标签和 _meta.filter 机制,为特定路由有条件地禁用全局插件。
工作原理
该方案使用三个组件:
- 路由标签:在需要跳过某些全局插件的路由上添加标签,例如
api7_disable_global_rules: response-rewrite。 serverless-pre-function:一个全局 serverless 函数,用于读取路由标签并将其注册为自定义 NGINX 变量。_meta.filter:全局插件上的条件表达式,用于评估变量,并在匹配时跳过执行。
前提条件
- API7 企业版实例正在运行。
- 已创建网关组,并且网关实例正在运行。
- Dashboard Token。
方案 1:正则匹配(推荐)
该方案返回原始路由标签字符串,并在全局插件上使用正则过滤器。它已在本地 API7 网关环境中通过全局 response-rewrite 规则完成端到端验证。
第 1 步:创建 Serverless 函数
将 serverless-pre-function 配置为全局插件,用于从路由标签注册自定义变量:
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/global_rules/serverless-pre-function?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function(conf, ctx) local core = require \"apisix.core\" core.ctx.register_var(\"api7_disable_global_rules\", function(ctx) local route = ctx.matched_route and ctx.matched_route.value if route and route.labels then return route.labels.api7_disable_global_rules end return 1 end) end"
]
}
}
}'
adc.yaml
global_rules:
serverless-pre-function:
phase: rewrite
functions:
- |-
return function(conf, ctx)
local core = require "apisix.core"
core.ctx.register_var("api7_disable_global_rules", function(ctx)
local route = ctx.matched_route and ctx.matched_route.value
if route and route.labels then
return route.labels.api7_disable_global_rules
end
return 1
end)
end
adc sync -f adc.yaml
第 2 步:使用 _meta.filter 配置全局插件
在你希望有条件跳过的全局插件中添加 _meta.filter。以下示例会默认全局添加响应头,除非路由标签包含 response-rewrite:
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/global_rules/response-rewrite?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"plugins": {
"response-rewrite": {
"headers": {
"set": {
"X-Global-Rule": "applied"
}
},
"_meta": {
"filter": [
["api7_disable_global_rules", "!", "~~", ".*response-rewrite.*"]
]
}
}
}
}'
adc.yaml
global_rules:
response-rewrite:
headers:
set:
X-Global-Rule: applied
_meta:
filter:
- - api7_disable_global_rules
- "!"
- "~~"
- ".*response-rewrite.*"
adc sync -f adc.yaml
第 3 步:为需要跳过插件的路由添加标签
将 api7_disable_global_rules 标签 添加到应绕过全局插件的路由上。
- Admin API
- ADC
# 1. 为路由创建服务
curl -k "https://localhost:7443/apisix/admin/services/global-exemption-service?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "global-exemption-service",
"upstream": {
"type": "roundrobin",
"nodes": [
{
"host": "httpbin.org",
"port": 80,
"weight": 100
}
]
}
}'
# 2. 创建跳过全局插件的带标签路由
curl -k "https://localhost:7443/apisix/admin/routes/global-exempt-route?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "global-exempt-route",
"paths": ["/anything/global-exempt"],
"methods": ["GET"],
"labels": {
"api7_disable_global_rules": "response-rewrite"
},
"service_id": "global-exemption-service"
}'
# 3. 创建仍应用全局插件的普通路由
curl -k "https://localhost:7443/apisix/admin/routes/global-protected-route?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "global-protected-route",
"paths": ["/anything/global-protected"],
"methods": ["GET"],
"service_id": "global-exemption-service"
}'
adc.yaml
services:
- name: global-exemption-service
upstream:
nodes:
- host: httpbin.org
port: 80
weight: 1
routes:
- name: global-exempt-route
uris:
- /anything/global-exempt
labels:
api7_disable_global_rules: response-rewrite
- name: global-protected-route
uris:
- /anything/global-protected
adc sync -f adc.yaml
验证
向带标签的路由发送请求:
curl -i "http://127.0.0.1:9080/anything/global-exempt"
由于 response-rewrite 被跳过,响应中不应包含 X-Global-Rule 请求头。
向未带标签的路由发送请求:
curl -i "http://127.0.0.1:9080/anything/global-protected"
由于全局插件处于激活状态,响应中应包含 X-Global-Rule: applied。
方案 2:基于列表匹配
该方案会从标签返回插件名称列表,并在 _meta.filter 中使用 has 操作符。
警告
与基于列表的方案相比,复杂正则表达式可能带来更多处理开销。
Serverless 函数
如果你更希望对逗号分隔标签进行精确列表成员检查,请使用以下变体:
adc.yaml
global_rules:
serverless-pre-function:
phase: rewrite
functions:
- >-
return function(conf, ctx)
local core = require "apisix.core"
core.ctx.register_var("api7_disable_global_rules", function(ctx)
local route = ctx.matched_route and ctx.matched_route.value
if route and route.labels then
local value = route.labels.api7_disable_global_rules
if value then
local disable_plugins = {}
for plugin_name in string.gmatch(value, "[^,]+") do
local trimmed_name = string.gsub(plugin_name, "^%s*(.-)%s*$", "%1")
if trimmed_name and trimmed_name ~= "" then
table.insert(disable_plugins, trimmed_name)
end
end
return disable_plugins
end
end
return 1
end)
end
使用 has 过滤器的全局插件
使用 has 操作符检查返回的列表是否包含插件名称:
adc.yaml
global_rules:
response-rewrite:
_meta:
filter:
- - api7_disable_global_rules
- "!"
- has
- response-rewrite
headers:
set:
X-Global-Rule: applied
理解 _meta.filter
_meta 字段适用于每个插件,并支持以下选项:
| 字段 | 类型 | 描述 |
|---|---|---|
disable | boolean | 完全禁用插件 |
error_response | string/object | 插件拒绝请求时使用的自定义错误响应 |
priority | integer | 覆盖插件执行优先级 |
filter | array | 运行时表达式;当表达式求值为 false 时跳过插件 |
filter 字段使用与路由匹配(radixtree vars)相同的表达式语法。支持的操作符包括 ==、!=、~~(正则)、has(列表包含)等。