API7 网关 AI Agent Skill:response-rewrite 插件
概览
response-rewrite 插件会在 API7 企业版向客户端返回响应前重写响应属性。
该插件会将响应返回给客户端。你可以无条件或根据匹配条件修改 HTTP 状态码、响应头和响应体。它在 header_filter 和 body_filter 阶段运行,因此即使前置插件(例如认证插件)调用 ngx.exit,它也会执行。
适用场景
- 覆盖返回给客户端的 HTTP 状态码。
- 添加、设置或移除响应头(例如安全请求头、CORS)。
- 替换整个响应体(静态内容、错误消息)。
- 使用正则表达式过滤器修改响应体的部分内容。
- 有条件地应用响应修改(例如仅针对特定状态码)。
- 提供经过 Base64 解码的二进制内容(图像、protobuf)。
插件配置参考(路由/服务)
| 字段 | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
status_code | integer | 否 | — | 新的 HTTP 状态码(200–598)。如果未设置,则使用原始状态码。 |
body | string | 否 | — | 新的响应体。Content-Length 会自动重置。不能与 filters 同时使用。 |
body_base64 | boolean | 否 | false | 在发送前将 body 从 Base64 解码。仅解码插件配置的响应体,不解码上游响应。 |
headers | object | 否 | — | 使用 set、add 和 remove 字段操作请求头。 |
headers.set | object | 否 | — | 设置(覆盖)响应头。值为键值对,支持 NGINX 变量。 |
headers.add | array[string] | 否 | — | 追加响应头。例如:["Name: value", ...]。即使请求头已存在也会添加。 |
headers.remove | array[string] | 否 | — | 移除响应头。要移除的请求头名称列表。 |
vars | array[array] | 否 | — | 使用 lua-resty-expr 语法进行条件匹配。仅当条件匹配时插件才会执行。 |
filters | array[object] | 否 | — | 用于修改响应体的正则过滤器。不能与 body 同时使用。 |
filters[].regex | string | 是 | — | 要在响应体中匹配的正则表达式。 |
filters[].replace | string | 是 | — | 替换内容。 |
filters[].scope | string | 否 | "once" | "once" 表示仅替换首次匹配,"global" 表示替换所有匹配。 |
filters[].options | string | 否 | "jo" | 正则表达式选项。参见 ngx.re.match。 |
互斥关系:body 和 filters 不能同时使用。
分步指南:在路由上启用 response-rewrite
1. 添加安全响应头
为 default 网关组添加安全请求头:
a7 route create --gateway-group default -f - <<'EOF'
{
"id": "security-headers",
"uri": "/api/*",
"plugins": {
"response-rewrite": {
"headers": {
"set": {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"Strict-Transport-Security": "max-age=31536000; includeSubDomains"
},
"remove": ["Server", "X-Powered-By"]
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF
2. 自定义错误响应体
a7 route create --gateway-group prod -f - <<'EOF'
{
"id": "custom-error",
"uri": "/maintenance/*",
"plugins": {
"response-rewrite": {
"status_code": 503,
"body": "{\"error\": \"Service under maintenance\", \"retry_after\": 300}",
"headers": {
"set": {
"Content-Type": "application/json",
"Retry-After": "300"
}
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF
3. 条件重写(仅针对 200 响应)
a7 route create --gateway-group stage -f - <<'EOF'
{
"id": "conditional-rewrite",
"uri": "/api/*",
"plugins": {
"response-rewrite": {
"headers": {
"set": {
"Cache-Control": "public, max-age=3600"
}
},
"vars": [["status", "==", 200]]
}
},
"upstream": {
"type": "roundrobin",
"nodes": [{"host": "backend", "port": 8080, "weight": 1}]
}
}
EOF
常见模式
正则响应体过滤器(全局替换文本)
使用公开 URL 替换响应体中的内部主机名:
{
"plugins": {
"response-rewrite": {
"filters": [
{
"regex": "http://internal\\.service\\.local",
"scope": "global",
"replace": "https://api.example.com"
}
]
}
}
}
多个正则过滤器
{
"plugins": {
"response-rewrite": {
"filters": [
{
"regex": "X-Amzn-Trace-Id",
"scope": "global",
"replace": "X-Trace-Id"
},
{
"regex": "\"debug\":\\s*true",
"scope": "global",
"replace": "\"debug\": false"
}
]
}
}
}
Base64 响应体(提供二进制内容)
{
"plugins": {
"response-rewrite": {
"status_code": 200,
"body": "SGVsbG8gV29ybGQ=",
"body_base64": true,
"headers": {
"set": {
"Content-Type": "text/plain"
}
}
}
}
}
返回解码后的响应体:Hello World
添加动态服务器信息请求头
{
"plugins": {
"response-rewrite": {
"headers": {
"set": {
"X-Served-By": "$balancer_ip:$balancer_port",
"X-Request-Id": "$request_id"
}
}
}
}
}
条件重写:仅重写 5xx 错误
{
"plugins": {
"response-rewrite": {
"body": "{\"error\": \"internal server error\", \"code\": 500}",
"headers": {
"set": {
"Content-Type": "application/json"
}
},
"vars": [["status", ">=", 500]]
}
}
}
重要注意事项
- 执行阶段:在
header_filter和body_filter阶段运行,因此即使前置插件(认证、限流)通过ngx.exit拒绝请求,也会执行。 - 请求头操作顺序:
add→remove→set。 - 响应体和 filters 互斥:不能同时设置
body和filters。 - Base64 解码:仅作用于插件配置的
body字段,不作用于上游响应体。
故障排查
| 现象 | 原因 | 解决方法 |
|---|---|---|
| 响应体未改变 | 同时设置了 body 和 filters | 只能选择一项:body 用于完整替换,filters 用于局部替换 |
| 状态码未改变 | status_code 不在有效范围内 | 必须为 200–598 |
| 正则过滤器未匹配 | 模式语法或转义有误 | 测试正则表达式;使用 "jo" 选项支持 UTF-8 |
| 移除后请求头仍存在 | 请求头名称大小写不匹配 | 请求头名称不区分大小写;检查拼写是否准确 |
| Vars 条件未生效 | 运算符或类型错误 | 使用 lua-resty-expr 语法:["status", "==", 200](整数而非字符串) |
| 认证失败时仍执行重写 | 这是预期行为 | 无论前置 ngx.exit 调用如何,插件都会在过滤阶段运行 |
| Content-Length 不匹配 | 手动设置了 Content-Length 请求头 | 不要手动设置 Content-Length,插件会自动重置该字段 |
| 配置未生效 | 指定了错误的网关组 | 确保 --gateway-group 与目标集群一致 |
配置同步示例
version: "1"
gateway_group: default
routes:
- id: response-transform
uri: /api/*
plugins:
response-rewrite:
headers:
set:
X-Content-Type-Options: "nosniff"
X-Frame-Options: "DENY"
remove:
- Server
- X-Powered-By
vars:
- ["status", "==", 200]
upstream:
type: roundrobin
nodes:
- host: backend
port: 8080
weight: 1
本页面由 api7/a7 仓库中的 a7-plugin-response-rewrite/SKILL.md 生成。你可以在 AI Agent Skills 页面查看所有技能。