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

API7 网关 AI Agent Skill:serverless 插件

概览

API7 企业版提供两个 serverless 插件,可在请求处理期间执行内联 Lua 函数:

  • serverless-pre-function — 在指定阶段的开始运行(优先级为 10000,较早执行)。
  • serverless-post-function — 在指定阶段的结束运行(优先级为 −2000,较晚执行)。

两个插件共享相同的配置。函数以 Lua 字符串的形式通过 Admin API 定义,并在加载时编译。

适用场景

  • 无需编写完整插件即可注入自定义请求/响应逻辑。
  • 快速实现请求头注入、重定向或日志记录原型。
  • 添加轻量级前置处理(重写)或后置处理(日志)。
  • 根据请求属性动态决定路由。

插件配置参考

字段类型是否必填默认值有效值说明
phasestring"access"rewrite, access, header_filter, body_filter, log, before_proxy函数执行的阶段
functionsarray[string]Lua 函数字符串函数按顺序执行;每个字符串都必须返回一个函数

函数签名

从 API7 企业版(基于 APISIX v2.6+)开始,函数接收两个参数:

return function(conf, ctx)
-- conf:插件配置对象
-- ctx:API7 企业版请求上下文(由各插件共享)
--
-- 可选返回值:
-- return code, body -- 立即退出并返回 HTTP 状态码和响应体
-- return -- 继续执行下一个函数或插件
end

规则:

  • 字符串必须返回一个函数,直接使用原始语句会被拒绝。
  • 函数会通过 LRU 缓存;更新路由以获取变更。

阶段执行顺序

1. rewrite         → 在路由匹配前修改请求
2. access → 执行授权和身份认证检查
3. before_proxy → 在调用上游前进行最后处理
4. header_filter → 修改响应头
5. body_filter → 修改响应体(通过 ngx.arg 分块处理)
6. log → 响应发送后的日志记录(只读)

阶段限制

阶段可读请求可修改请求可修改响应可退出
rewrite
access
before_proxy
header_filter✅ (请求头)
body_filter✅(响应体分块)
日志

分步示例

1. 基本日志记录

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "serverless-log",
"uri": "/api/*",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function() ngx.log(ngx.WARN, 'incoming request: ', ngx.var.uri) end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

2. HTTP 到 HTTPS 重定向

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "force-https",
"uri": "/*",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function() if ngx.var.scheme == 'http' then ngx.header['Location'] = 'https://' .. ngx.var.host .. ngx.var.request_uri; ngx.exit(301) end end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

3. 注入请求头

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "inject-headers",
"uri": "/api/*",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function(conf, ctx) ngx.req.set_header('X-Request-ID', ngx.var.request_id); ngx.req.set_header('X-Real-IP', ngx.var.remote_addr) end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

4. 修改上游 URI

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "rewrite-uri",
"uri": "/legacy/*",
"plugins": {
"serverless-post-function": {
"phase": "access",
"functions": [
"return function(conf, ctx) ctx.var.upstream_uri = '/v2' .. ngx.var.uri end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

5. 修改响应头(header_filter 阶段)

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "resp-headers",
"uri": "/api/*",
"plugins": {
"serverless-post-function": {
"phase": "header_filter",
"functions": [
"return function() ngx.header['X-Processed-By'] = 'API7-EE'; ngx.header['X-Response-Time'] = ngx.now() - ngx.req.start_time() end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

6. 使用持久状态的闭包

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "closure-counter",
"uri": "/count",
"plugins": {
"serverless-pre-function": {
"phase": "log",
"functions": [
"local count = 0; return function() count = count + 1; ngx.log(ngx.WARN, 'request count: ', count) end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

7. 多个顺序执行的函数

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "multi-fn",
"uri": "/api/*",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function() ngx.log(ngx.WARN, 'step one') end",
"return function() ngx.log(ngx.WARN, 'step two') end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

8. 自定义身份认证保护

a7 route create --gateway-group default -f - <<'EOF'
{
"id": "custom-auth",
"uri": "/admin/*",
"plugins": {
"serverless-pre-function": {
"phase": "access",
"functions": [
"return function() local token = ngx.var.http_authorization; if not token or token ~= 'Bearer secret123' then return 401, '{\"error\":\"unauthorized\"}' end end"
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF

可用 Lua API

核心 ngx API

-- 请求
ngx.var.uri, ngx.var.request_uri, ngx.var.scheme, ngx.var.host
ngx.var.remote_addr, ngx.var.request_method, ngx.var.request_id
ngx.req.get_headers(), ngx.req.get_uri_args(), ngx.req.get_method()
ngx.req.set_header(name, value), ngx.req.read_body(), ngx.req.get_body_data()

-- 响应
ngx.header["Name"] = "value"
ngx.status = 200
ngx.say(data), ngx.print(data)
ngx.exit(status), ngx.redirect(uri, status)

-- 日志
ngx.log(ngx.ERR, msg), ngx.log(ngx.WARN, msg), ngx.log(ngx.INFO, msg)

-- 工具函数
ngx.time(), ngx.now(), ngx.encode_base64(str), ngx.decode_base64(str)

API7 企业版上下文变量

ctx.var.upstream_uri = "/new/path"   -- 修改上游请求 URI
ctx.curr_req_matched._path -- 匹配的路由路径
ctx.consumer_name -- 已认证的消费者名称
ctx.route_id -- 当前路由 ID
ctx.service_id -- 当前服务 ID

可用库

local json = require("cjson")
local core = require("apisix.core")
local http = require("resty.http")
local lrucache = require("resty.lrucache")

配置同步示例

version: "1"
gateway_group: default
routes:
- id: serverless-demo
uri: /api/*
plugins:
serverless-pre-function:
phase: rewrite
functions:
- "return function() ngx.req.set_header('X-Gateway', 'api7-ee') end"
serverless-post-function:
phase: log
functions:
- "return function() ngx.log(ngx.WARN, 'request completed') end"
upstream:
type: roundrobin
nodes:
- host: backend
port: 8080
weight: 1

关键差异:Pre 与 Post

特性serverless-pre-functionserverless-post-function
执行时机阶段开始阶段结束
优先级10000(高——较早运行)−2000(低——较晚运行)
典型用途前置处理、认证保护后置处理、日志记录

故障排查

现象原因解决方法
only accept Lua function, input code type is nil函数字符串未返回函数使用 return function() ... end 包装代码
failed to compile functionLua 代码存在语法错误先在 Lua REPL 中测试代码
函数变更未生效LRU 缓存保留了旧的已编译函数更新路由以触发重新编译
ngx.say 在 header_filter 中无效阶段限制:header_filter 不能写入响应体在 header_filter 中仅使用 ngx.header 进行修改
日志阶段没有输出日志阶段为只读使用 ngx.log(),不要使用 ngx.say()
阻塞 I/O 导致超时请求路径中存在同步操作使用 ngx.timer.at() 执行异步工作

本页面由 api7/a7 仓库中的 a7-plugin-serverless/SKILL.md 生成。你可以在 AI Agent Skills 页面查看所有技能。