response-rewrite
The response-rewrite plugin offers options to rewrite responses that APISIX and its upstream services return to clients. With the plugin, you can modify HTTP status codes, request headers, response body, and more.
For instance, you can use this plugin to:
- Support CORS by setting
Access-Control-Allow-*headers. - Indicate redirection by setting HTTP status codes and
Locationheader.
Examples
The examples below demonstrate how you can configure response-rewrite on a route in different scenarios.
Rewrite Header and Body
The following example demonstrates how to add response body and headers, only to responses with 200 HTTP status codes.
Create a route with the response-rewrite plugin:
- 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
Synchronize the configuration to the gateway:
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
Apply the configuration to your cluster:
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
Apply the configuration to your cluster:
kubectl apply -f response-rewrite-ic.yaml
Send a request to verify:
curl -i "http://127.0.0.1:9080/headers"
You should receive a HTTP/1.1 200 OK response similar to the following:
...
X-Server-id: 3
X-Server-status: on
X-Server-balancer-addr: 50.237.103.220:80
{"code":"ok","message":"new json body"}
Rewrite Header With RegEx Filter
The following example demonstrates how to use RegEx filter matching to replace X-Amzn-Trace-Id for responses.
Create a route with the response-rewrite plugin:
- 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
Synchronize the configuration to the gateway:
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
Apply the configuration to your cluster:
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
Apply the configuration to your cluster:
kubectl apply -f response-rewrite-ic.yaml
Send a request to verify:
curl -i "http://127.0.0.1:9080/headers"
You should see a response similar to the following:
{
"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"
}
}
Decode Body from Base64
The following example demonstrates how to Decode Body from Base64 format.
Create a route with the response-rewrite plugin:
- 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
Synchronize the configuration to the gateway:
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
Apply the configuration to your cluster:
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
Apply the configuration to your cluster:
kubectl apply -f response-rewrite-ic.yaml
Send a request to verify:
curl "http://127.0.0.1:9080/get"
You should see a response of the following:
Hello World
Rewrite Response and Its Connection with Execution Phases
The following example demonstrates the connection between the response-rewrite plugin and execution phases by configuring the plugin with the key-auth plugin, and see how the response is still rewritten to 200 OK in the case of an unauthenticated request.
- Admin API
- ADC
- Ingress Controller
Create a consumer jack:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack"
}'
Create key-auth credential for the consumer:
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"
}
}
}'
Create a route with key-auth and configure response-rewrite to rewrite the response status code and body:
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
}
}
}'
Create a consumer with key-auth credential and a route with key-auth and response-rewrite plugins configured as such:
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
Synchronize the configuration to the gateway:
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
Apply the configuration to your cluster:
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"}'
Apply the configuration to your cluster:
kubectl apply -f response-rewrite-ic.yaml
Send a request to the route with the valid key:
curl -i "http://127.0.0.1:9080/get" -H 'apikey: jack-key'
You should receive an HTTP/1.1 200 OK response of the following:
{"code": 200, "msg": "success"}
Send a request to the route without any key:
curl -i "http://127.0.0.1:9080/get"
You should still receive an HTTP/1.1 200 OK response of the same, instead of HTTP/1.1 401 Unauthorized from the key-auth plugin. This shows that the response-rewrite plugin still rewrites the response.
This is because header_filter and body_filter phase logics of the response-rewrite plugin will continue to run after ngx.exit in the access or rewrite phases from other plugins.
The following table summarizes the impact of ngx.exit on execution phases.
| Phase | rewrite | access | header_filter | body_filter |
|---|---|---|---|---|
| rewrite | ngx.exit | |||
| access | × | ngx.exit | ||
| header_filter | ✓ | ✓ | ngx.exit | |
| body_filter | ✓ | ✓ | × | ngx.exit |
For example, if ngx.exit takes places in the rewrite phase, it will interrupt the execution of access phase but not interfere with header_filter and body_filter phases.