跳到主要内容
版本:3.10.x

条件式禁用全局插件

全局插件默认应用于所有路由,这对于强制执行组织级策略非常有用,例如日志记录、改写或流量控制。不过,有些路由可能需要从某些全局插件中豁免。

本指南将介绍如何使用路由标签和 _meta.filter 机制,为特定路由有条件地禁用全局插件。

工作原理

该方案使用三个组件:

  1. 路由标签:在需要跳过某些全局插件的路由上添加标签,例如 api7_disable_global_rules: response-rewrite
  2. serverless-pre-function:一个全局 serverless 函数,用于读取路由标签并将其注册为自定义 NGINX 变量。
  3. _meta.filter:全局插件上的条件表达式,用于评估变量,并在匹配时跳过执行。

前提条件

  • API7 企业版实例正在运行。
  • 已创建网关组,并且网关实例正在运行。
  • Dashboard Token

方案 1:正则匹配(推荐)

该方案返回原始路由标签字符串,并在全局插件上使用正则过滤器。它已在本地 API7 网关环境中通过全局 response-rewrite 规则完成端到端验证。

第 1 步:创建 Serverless 函数

serverless-pre-function 配置为全局插件,用于从路由标签注册自定义变量:

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"
]
}
}
}'

第 2 步:使用 _meta.filter 配置全局插件

在你希望有条件跳过的全局插件中添加 _meta.filter。以下示例会默认全局添加响应头,除非路由标签包含 response-rewrite

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.*"]
]
}
}
}
}'

第 3 步:为需要跳过插件的路由添加标签

api7_disable_global_rules 标签添加到应绕过全局插件的路由上。

# 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"
}'

验证

向带标签的路由发送请求:

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 字段适用于每个插件,并支持以下选项:

字段类型描述
disableboolean完全禁用插件
error_responsestring/object插件拒绝请求时使用的自定义错误响应
priorityinteger覆盖插件执行优先级
filterarray运行时表达式;当表达式求值为 false 时跳过插件

filter 字段使用与路由匹配(radixtree vars)相同的表达式语法。支持的操作符包括 ==!=~~(正则)、has(列表包含)等。

其他资源