response-rewrite
response-rewrite 插件提供了重写 APISIX 及其上游服务返回给客户端的响应的选项。使用该插件,你可以修改 HTTP 状态码、响应头、响应体等。
例如,你可以使用此插件来:
- 通过设置
Access-Control-Allow-*头来支持 CORS。 - 通过设置 HTTP 状态码和
Location头来指示重定向。
示例
以下示例展示了如何在不同场景下的路由上配置 response-rewrite。
重写响应头和响应体
以下示例演示了如何仅对具有 200 HTTP 状态码的响应添加响应体和响应头。
创建一个带有 response-rewrite 插件的路由:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "response-rewrite-route",
"methods": ["GET"],
"uri": "/headers",
"plugins": {
"response-rewrite": {
"body": "{\"code\":\"ok\",\"message\":\"new json body\"}",
"headers": {
"set": {
"X-Server-id": 3,
"X-Server-status": "on",
"X-Server-balancer-addr": "$balancer_ip:$balancer_port"
}
},
"vars": [
[ "status","==",200 ]
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
services:
- name: httpbin
routes:
- uris:
- /headers
name: response-rewrite-route
methods:
- GET
plugins:
response-rewrite:
body: '{"code":"ok","message":"new json body"}'
headers:
set:
X-Server-id: 3
X-Server-status: "on"
X-Server-balancer-addr: "$balancer_ip:$balancer_port"
vars:
- - status
- "=="
- 200
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
将配置同步到网关:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: response-rewrite-plugin-config
spec:
plugins:
- name: response-rewrite
config:
body: '{"code":"ok","message":"new json body"}'
headers:
set:
X-Server-id: 3
X-Server-status: "on"
X-Server-balancer-addr: "$balancer_ip:$balancer_port"
vars:
- - status
- "=="
- 200
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: response-rewrite-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /headers
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: response-rewrite-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
将配置应用到集群:
kubectl apply -f response-rewrite-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: response-rewrite-route
spec:
ingressClassName: apisix
http:
- name: response-rewrite-route
match:
paths:
- /headers
upstreams:
- name: httpbin-external-domain
plugins:
- name: response-rewrite
enable: true
config:
body: '{"code":"ok","message":"new json body"}'
headers:
set:
X-Server-id: 3
X-Server-status: "on"
X-Server-balancer-addr: "$balancer_ip:$balancer_port"
vars:
- - status
- "=="
- 200
将配置应用到集群:
kubectl apply -f response-rewrite-ic.yaml
发送请求以进行验证:
curl -i "http://127.0.0.1:9080/headers"
你应该收到类似于以下的 HTTP/1.1 200 OK 响应:
...
X-Server-id: 3
X-Server-status: on
X-Server-balancer-addr: 50.237.103.220:80
{"code":"ok","message":"new json body"}
使用正则过滤器重写响应头
以下示例演示了如何使用正则过滤器匹配来替换响应的 X-Amzn-Trace-Id。
创建一个带有 response-rewrite 插件的路由:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "response-rewrite-route",
"methods": ["GET"],
"uri": "/headers",
"plugins":{
"response-rewrite":{
"filters":[
{
"regex":"X-Amzn-Trace-Id",
"scope":"global",
"replace":"X-Amzn-Trace-Id-Replace"
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
services:
- name: httpbin
routes:
- uris:
- /headers
name: response-rewrite-route
methods:
- GET
plugins:
response-rewrite:
filters:
- regex: X-Amzn-Trace-Id
scope: global
replace: X-Amzn-Trace-Id-Replace
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
将配置同步到网关:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: response-rewrite-plugin-config
spec:
plugins:
- name: response-rewrite
config:
filters:
- regex: X-Amzn-Trace-Id
scope: global
replace: X-Amzn-Trace-Id-Replace
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: response-rewrite-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /headers
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: response-rewrite-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
将配置应用到集群:
kubectl apply -f response-rewrite-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: response-rewrite-route
spec:
ingressClassName: apisix
http:
- name: response-rewrite-route
match:
paths:
- /headers
upstreams:
- name: httpbin-external-domain
plugins:
- name: response-rewrite
enable: true
config:
filters:
- regex: X-Amzn-Trace-Id
scope: global
replace: X-Amzn-Trace-Id-Replace
将配置应用到集群:
kubectl apply -f response-rewrite-ic.yaml
发送请求以进行验证:
curl -i "http://127.0.0.1:9080/headers"
你应该看到类似于以下的响应:
{
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.2.1",
"X-Amzn-Trace-Id-Replace": "Root=1-6500095d-1041b05e2ba9c6b37232dbc7",
"X-Forwarded-Host": "127.0.0.1"
}
}
解码 Base64 格式的响应体
以下示例演示了如何解码 Base64 格式的响应体。
创建一个带有 response-rewrite 插件的路由:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "response-rewrite-route",
"methods": ["GET"],
"uri": "/get",
"plugins":{
"response-rewrite": {
"body": "SGVsbG8gV29ybGQ=",
"body_base64": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
services:
- name: httpbin
routes:
- uris:
- /get
name: response-rewrite-route
methods:
- GET
plugins:
response-rewrite:
body: SGVsbG8gV29ybGQ=
body_base64: true
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
将配置同步到网关:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: response-rewrite-plugin-config
spec:
plugins:
- name: response-rewrite
config:
body: SGVsbG8gV29ybGQ=
body_base64: true
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: response-rewrite-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /get
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: response-rewrite-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
将配置应用到集群:
kubectl apply -f response-rewrite-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: response-rewrite-route
spec:
ingressClassName: apisix
http:
- name: response-rewrite-route
match:
paths:
- /get
upstreams:
- name: httpbin-external-domain
plugins:
- name: response-rewrite
enable: true
config:
body: SGVsbG8gV29ybGQ=
body_base64: true
将配置应用到集群:
kubectl apply -f response-rewrite-ic.yaml
发送请求以进行验证:
curl "http://127.0.0.1:9080/get"
你应该看到以下响应:
Hello World
重写响应及其与执行阶段的联系
以下示例演示了 response-rewrite 插件与执行阶段之间的联系,通过配置带有 key-auth 插件的 response-rewrite 插件,观察在未经身份认证的请求情况下,响应如何仍然被重写为 200 OK。
- Admin API
- ADC
- Ingress Controller
创建一个消费者 jack:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack"
}'
为消费者创建 key-auth 凭证:
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-jack-key-auth",
"plugins": {
"key-auth": {
"key": "jack-key"
}
}
}'
创建一个带有 key-auth 的路由,并配置 response-rewrite 以重写响应状态码和响应体:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "response-rewrite-route",
"uri": "/get",
"plugins": {
"key-auth": {},
"response-rewrite": {
"status_code": 200,
"body": "{\"code\": 200, \"msg\": \"success\"}"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
创建一个配置了 key-auth 凭证的消费者,以及一个配置了 key-auth 和 response-rewrite 插件的路由:
consumers:
- username: jack
credentials:
- name: cred-jack-key-auth
type: key-auth
config:
key: jack-key
services:
- name: httpbin
routes:
- name: response-rewrite-route
uris:
- /get
plugins:
key-auth: {}
response-rewrite:
status_code: 200
body: '{"code": 200, "msg": "success"}'
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
将配置同步到网关:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: apisix.apache.org/v1alpha1
kind: Consumer
metadata:
namespace: aic
name: jack
spec:
gatewayRef:
name: apisix
credentials:
- type: key-auth
name: cred-jack-key-auth
config:
key: jack-key
---
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: response-rewrite-plugin-config
spec:
plugins:
- name: key-auth
config:
_meta:
disable: false
- name: response-rewrite
config:
status_code: 200
body: '{"code": 200, "msg": "success"}'
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: response-rewrite-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /get
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: response-rewrite-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
将配置应用到集群:
kubectl apply -f response-rewrite-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixConsumer
metadata:
namespace: aic
name: jack
spec:
ingressClassName: apisix
authParameter:
keyAuth:
value:
key: jack-key
---
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: response-rewrite-route
spec:
ingressClassName: apisix
http:
- name: response-rewrite-route
match:
paths:
- /get
upstreams:
- name: httpbin-external-domain
plugins:
- name: key-auth
enable: true
- name: response-rewrite
enable: true
config:
status_code: 200
body: '{"code": 200, "msg": "success"}'
将配置应用到集群:
kubectl apply -f response-rewrite-ic.yaml
使用有效密钥向路由发送请求:
curl -i "http://127.0.0.1:9080/get" -H 'apikey: jack-key'
你应该收到如下所示的 HTTP/1.1 200 OK 响应:
{"code": 200, "msg": "success"}
向路由发送不带任何密钥的请求:
curl -i "http://127.0.0.1:9080/get"
你仍然应该收到相同的 HTTP/1.1 200 OK 响应,而不是来自 key-auth 插件的 HTTP/1.1 401 Unauthorized。这表明 response-rewrite 插件仍然重写了响应。
这是因为 response-rewrite 插件的 header_filter 和 body_filter 阶段逻辑将在其他插件的 access 或 rewrite 阶段中的 ngx.exit 之后继续运行。
下表总结了 ngx.exit 对执行阶段的影响。
| 阶段 | rewrite | access | header_filter | body_filter |
|---|---|---|---|---|
| rewrite | ngx.exit | |||
| access | × | ngx.exit | ||
| header_filter | ✓ | ✓ | ngx.exit | |
| body_filter | ✓ | ✓ | × | ngx.exit |
例如,如果 ngx.exit 发生在 rewrite 阶段,它将中断 access 阶段的执行,但不会干扰 header_filter 和 body_filter 阶段。