diff --git a/docs/en/latest/plugins/response-rewrite.md b/docs/en/latest/plugins/response-rewrite.md index 467fc60ee474..3db85766279d 100644 --- a/docs/en/latest/plugins/response-rewrite.md +++ b/docs/en/latest/plugins/response-rewrite.md @@ -6,7 +6,7 @@ keywords: - Plugin - Response Rewrite - response-rewrite -description: This document contains information about the Apache APISIX response-rewrite Plugin. +description: 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. --- + + + + ## Description -The `response-rewrite` Plugin rewrites the content returned by the [Upstream](../terminology/upstream.md) and APISIX. +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. -This Plugin can be useful in these scenarios: +For instance, you can use this Plugin to: -- To set `Access-Control-Allow-*` field for supporting [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). -- To set custom `status_code` and `Location` fields in the header to redirect. +- Support [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) by setting `Access-Control-Allow-*` headers. +- Indicate redirection by setting HTTP status codes and `Location` header. :::tip -You can also use the [redirect](./redirect.md) Plugin to setup redirects. +You can also use the [redirect](./redirect.md) Plugin to set up redirects. ::: @@ -48,30 +52,25 @@ You can also use the [redirect](./redirect.md) Plugin to setup redirects. | Name | Type | Required | Default | Valid values | Description | |-----------------|---------|----------|---------|---------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | status_code | integer | False | | [200, 598] | New HTTP status code in the response. If unset, falls back to the original status code. | -| body | string | False | | | New body of the response. The content-length would also be reset. | -| body_base64 | boolean | False | false | | When set, the body passed in `body` will be decoded before writing to the client which is used in some image and Protobuffer scenarios. Note that this field only allows decoding the body passed in plugin configuration and does not decode upstream response. | -| headers | object | False | | | | -| headers.add | array | False | | | Append the new headers to the response. The format is `["name: value", ...]`. The values in the header can contain Nginx variables like `$remote_addr` and `$balancer_ip`. | -| headers.set | object | False | | | Rewriting the headers. The format is `{"name": "value", ...}`. The values in the header can contain Nginx variables like `$remote_addr` and `$balancer_ip`. | -| headers.remove | array | False | | | Remove the headers. The format is `["name", ...]`. | -| vars | array[] | False | | See [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list) for a list of available operators. | Nginx variable expressions to conditionally execute the rewrite. The Plugin will be executed unconditionally if this value is empty. | -| filters | array[] | False | | | List of filters that modify the response body by replacing one specified string with another. | -| filters.regex | string | True | | | Regex pattern to match on the response body. | -| filters.scope | string | False | "once" | "once","global" | Range to substitute. `once` substitutes the first match of `filters.regex` and `global` does global substitution. | -| filters.replace | string | True | | | Content to substitute with. | -| filters.options | string | False | "jo" | | Regex options. See [ngx.re.match](https://github.com/openresty/lua-nginx-module#ngxrematch). | +| body | string | False | | | New response body. The `Content-Length` header would also be reset. Should not be configured with `filters`. | +| body_base64 | boolean | False | false | | If true, decode the response body configured in `body` before sending to client, which is useful for image and protobuf decoding. Note that this configuration cannot be used to decode Upstream response. | +| headers | object | False | | | Actions to be executed in the order of `add`, `remove`, and `set`. | +| headers.add | array[string] | False | | | Headers to append to requests. If a header already present in the request, the header value will be appended. Header value could be set to a constant, or one or more [Nginx variables](https://nginx.org/en/docs/http/ngx_http_core_module.html). | +| headers.set | object | False | | |Headers to set to requests. If a header already present in the request, the header value will be overwritten. Header value could be set to a constant, or one or more[Nginx variables](https://nginx.org/en/docs/http/ngx_http_core_module.html). | +| headers.remove | array[string] | False | | | Headers to remove from requests. | +| vars | array[array] | False | | | An array of one or more matching conditions in the form of [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list). | +| filters | array[object] | False | | | List of filters that modify the response body by replacing one specified string with another. Should not be configured with `body`. | +| filters.regex | string | True | | | RegEx pattern to match on the response body. | +| filters.scope | string | False | "once" | ["once","global"] | Scope of substitution. `once` substitutes the first matched instance and `global` substitutes globally. | +| filters.replace | string | True | | | Content to substitute with. | +| filters.options | string | False | "jo" | | RegEx options to control how the match operation should be performed. See [Lua NGINX module](https://github.com/openresty/lua-nginx-module#ngxrematch) for the available options. | + +## Examples + +The examples below demonstrate how you can configure `response-rewrite` on a Route in different scenarios. :::note -Only one of `body` or `filters` can be configured. - -::: - -## Enable Plugin - -The example below enables the `response-rewrite` Plugin on a specific Route: - -:::note You can fetch the `admin_key` from `config.yaml` and save to an environment variable with the following command: ```bash @@ -80,175 +79,235 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ ::: +### 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: + ```shell -curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d ' -{ +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "response-rewrite-route", "methods": ["GET"], - "uri": "/test/index.html", + "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 ] - ] - } + "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": { - "127.0.0.1:80": 1 - } + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } } -}' + }' ``` -Here, `vars` is configured to run the Plugin only on responses with a 200 status code. - -Besides `set` operation, you can also `add` or `remove` response header like: - -```json -"headers": { - "add": [ - "X-Server-balancer-addr: $balancer_ip:$balancer_port" - ], - "remove": [ - "X-TO-BE-REMOVED" - ] -} -``` - -The execution order among those operations are ["add", "set", "remove"]. - -If you are using the deprecated `headers` configuration which puts the headers directly under `headers`, -you need to move them to `headers.set`. - -## Example usage - -Once you have enabled the Plugin as shown above, you can make a request: +Send a request to verify: ```shell -curl -X GET -i http://127.0.0.1:9080/test/index.html +curl -i "http://127.0.0.1:9080/headers" ``` -The response will be as shown below no matter what the response is from the Upstream: +You should receive a `HTTP/1.1 200 OK` response similar to the following: -``` -HTTP/1.1 200 OK -Date: Sat, 16 Nov 2019 09:15:12 GMT -Transfer-Encoding: chunked -Connection: keep-alive +```text +... X-Server-id: 3 X-Server-status: on -X-Server-balancer-addr: 127.0.0.1:80 +X-Server-balancer-addr: 50.237.103.220:80 {"code":"ok","message":"new json body"} ``` -:::info IMPORTANT +### Rewrite Header With RegEx Filter -[ngx.exit](https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/#ngxexit) will interrupt the execution of a request and returns its status code to Nginx. +The following example demonstrates how to use RegEx filter matching to replace `X-Amzn-Trace-Id` for responses. -However, if `ngx.exit` is executed during an access phase, it will only interrupt the request processing phase and the response phase will still continue to run. - -So, if you have configured the `response-rewrite` Plugin, it do a force overwrite of the response. - -| Phase | rewrite | access | header_filter | body_filter | -|---------------|----------|----------|---------------|-------------| -| rewrite | ngx.exit | √ | √ | √ | -| access | × | ngx.exit | √ | √ | -| header_filter | √ | √ | ngx.exit | √ | -| body_filter | √ | √ | × | ngx.exit | - -::: - -The example below shows how you can replace a key in the response body. Here, the key X-Amzn-Trace-Id is replaced with X-Amzn-Trace-Id-Replace by configuring the filters attribute using regex: +Create a Route with the `response-rewrite` plugin: ```shell -curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d ' -{ - "plugins":{ - "response-rewrite":{ - "headers":{ - "set": { - "X-Server-id":3, - "X-Server-status":"on", - "X-Server-balancer-addr":"$balancer_ip:$balancer_port" - } - }, - "filters":[ - { - "regex":"X-Amzn-Trace-Id", - "scope":"global", - "replace":"X-Amzn-Trace-Id-Replace" - } - ], - "vars":[ - [ - "status", - "==", - 200 +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_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", - "scheme":"https", - "nodes":{ - "httpbin.org:443":1 + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } } - }, - "uri":"/*" -}' + }' ``` +Send a request to verify: + ```shell -curl -X GET -i http://127.0.0.1:9080/get +curl -i "http://127.0.0.1:9080/headers" ``` -```shell -HTTP/1.1 200 OK -Transfer-Encoding: chunked -X-Server-status: on -X-Server-balancer-addr: 34.206.80.189:443 -X-Server-id: 3 +You should see a response similar to the following: +```text { - "args": {}, "headers": { "Accept": "*/*", "Host": "127.0.0.1", - "User-Agent": "curl/7.29.0", - "X-Amzn-Trace-Id-Replace": "Root=1-629e0b89-1e274fdd7c23ca6e64145aa2", + "User-Agent": "curl/8.2.1", + "X-Amzn-Trace-Id-Replace": "Root=1-6500095d-1041b05e2ba9c6b37232dbc7", "X-Forwarded-Host": "127.0.0.1" - }, - "origin": "127.0.0.1, 117.136.46.203", - "url": "https://127.0.0.1/get" + } } - ``` -## Delete Plugin +### Decode Body from Base64 + +The following example demonstrates how to Decode Body from Base64 format. -To remove the `response-rewrite` Plugin, you can delete the corresponding JSON configuration from the Plugin configuration. APISIX will automatically reload and you do not have to restart for this to take effect. +Create a Route with the `response-rewrite` plugin: ```shell -curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d ' -{ +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "response-rewrite-route", "methods": ["GET"], - "uri": "/test/index.html", - "upstream": { - "type": "roundrobin", - "nodes": { - "127.0.0.1:80": 1 + "uri": "/get", + "plugins":{ + "response-rewrite": { + "body": "SGVsbG8gV29ybGQ=", + "body_base64": true } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' +``` + +Send a request to verify: + +```shell +curl "http://127.0.0.1:9080/get" +``` + +You should see a response of the following: + +```text +Hello World +``` + +### Rewrite Response and Its Connection with Execution Phases + +The following example demonstrates the connection between the `response-rewrite` Plugin and [execution phases](/apisix/key-concepts/plugins#plugins-execution-lifecycle) 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. + +Create a consumer `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +Create `key-auth` credential for the consumer: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_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: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_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 + } } -}' + }' +``` + +Send a request to the Route with the valid key: + +```shell +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: + +```text +{"code": 200, "msg": "success"} ``` + +Send a request to the Route without any key: + +```shell +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`](https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/#ngxexit) 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. diff --git a/docs/zh/latest/plugins/response-rewrite.md b/docs/zh/latest/plugins/response-rewrite.md index 936be773da8b..3e0a08dd6016 100644 --- a/docs/zh/latest/plugins/response-rewrite.md +++ b/docs/zh/latest/plugins/response-rewrite.md @@ -6,7 +6,7 @@ keywords: - Plugin - Response Rewrite - response-rewrite -description: 本文介绍了关于 Apache APISIX `response-rewrite` 插件的基本信息及使用方法。 +description: response-rewrite 插件提供了重写 APISIX 及其上游服务返回给客户端的响应的选项。使用该插件,您可以修改 HTTP 状态代码、请求标头、响应正文等。 --- + + + + ## 描述 -`response-rewrite` 插件支持修改上游服务或 APISIX 返回的 Body 和 Header 信息。 +`response-rewrite` 插件提供了重写 APISIX 及其上游服务返回给客户端的响应的选项。使用此插件,您可以修改 HTTP 状态代码、请求标头、响应正文等。 -该插件可以应用在以下场景中: +例如,您可以使用此插件来: -- 通过设置 `Access-Control-Allow-*` 字段实现 CORS(跨域资源共享)的功能。 -- 通过设置标头中的 `status_code` 和 `Location` 字段实现重定向。 +- 通过设置 `Access-Control-Allow-*` 标头来支持 [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)。 +- 通过设置 HTTP 状态代码和 `Location` 标头来指示重定向。 :::tip @@ -48,28 +52,22 @@ description: 本文介绍了关于 Apache APISIX `response-rewrite` 插件的基 | 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 | |-----------------|---------|--------|--------|-----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | status_code | integer | 否 | | [200, 598] | 修改上游返回状态码,默认保留原始响应代码。 | -| body | string | 否 | | | 修改上游返回的 `body` 内容,如果设置了新内容,header 里面的 content-length 字段也会被去掉。 | -| body_base64 | boolean | 否 | false | | 当设置时,在写给客户端之前,在`body`中传递的主体将被解码,这在一些图像和 Protobuffer 场景中使用。注意,这个字段只允许对插件配置中传递的主体进行解码,并不对上游响应进行解码。 | -| headers | object | 否 | | | | -| headers.add | array | 否 | | | 添加新的响应头。格式为 `["name: value", ...]`。这个值能够以 `$var` 的格式包含 NGINX 变量,比如 `$remote_addr $balancer_ip`。 | -| headers.set | object | 否 | | | 改写响应头。格式为 `{"name": "value", ...}`。这个值能够以 `$var` 的格式包含 NGINX 变量,比如 `$remote_addr $balancer_ip`。 | -| headers.remove | array | 否 | | | 移除响应头。格式为 `["name", ...]`。 | -| vars | array[] | 否 | | | `vars` 是一个表达式列表,只有满足条件的请求和响应才会修改 body 和 header 信息,来自 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list)。如果 `vars` 字段为空,那么所有的重写动作都会被无条件的执行。 | -| filters | array[] | 否 | | | 一组过滤器,采用指定字符串表达式修改响应体。 | -| filters.regex | string | 是 | | | 用于匹配响应体正则表达式。 | -| filters.scope | string | 否 | "once" | "once","global" | 替换范围,"once" 表达式 `filters.regex` 仅替换首次匹配上响应体的内容,"global" 则进行全局替换。 | -| filters.replace | string | 是 | | | 替换后的内容。 | -| filters.options | string | 否 | "jo" | | 正则匹配有效参数,可选项见 [ngx.re.match](https://github.com/openresty/lua-nginx-module#ngxrematch)。 | - -:::note - -`body` 和 `filters` 属性只能配置其中一个。 - -::: - -## 启用插件 - -你可以通过如下命令在指定路由上启用 `response-rewrite` 插件: +| body | string | 否 | | | 修改上游返回的 `body` 内容,如果设置了新内容,header 里面的 `Content-Length` 字段也会被去掉。 | +| body_base64 | boolean | 否 | false | | 如果为 true,则在发送到客户端之前解码`body` 中配置的响应主体,这对于图像和 protobuf 解码很有用。请注意,此配置不能用于解码上游响应。 | +| headers | object | 否 | | | 按照 `add`、`remove` 和 `set` 的顺序执行的操作。 | +| headers.add | array[string] | 否 | | | 要附加到请求的标头。如果请求中已经存在标头,则会附加标头值。标头值可以设置为常量,也可以设置为一个或多个 [Nginx 变量](https://nginx.org/en/docs/http/ngx_http_core_module.html)。 | +| headers.set | object | 否 | | |要设置到请求的标头。如果请求中已经存在标头,则会覆盖标头值。标头值可以设置为常量,也可以设置为一个或多个[Nginx 变量](https://nginx.org/en/docs/http/ngx_http_core_module.html)。 | +| headers.remove | array[string] | 否 | | | 要从请求中删除的标头。 | +| vars | array[array] | 否 | | | 以 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list) 的形式包含一个或多个匹配条件的数组。 | +| filters | array[object] | 否 | | | 通过将一个指定字符串替换为另一个指定字符串来修改响应主体的过滤器列表。不应与 `body` 一起配置。 | +| filters.regex | string | True | | | 用于匹配响应主体的 RegEx 模式。 | +| filters.scope | string | 否 | "once" | ["once","global"] | 替换范围。`once` 替换第一个匹配的实例,`global` 全局替换。 | +| filters.replace | string | True | | | 要替换的内容。 | +| filters.options | string | 否 | "jo" | | 用于控制如何执行匹配操作的 RegEx 选项。请参阅[Lua NGINX 模块](https://github.com/openresty/lua-nginx-module#ngxrematch)以了解可用选项。| + +## 示例 + +以下示例演示了如何在不同场景中在路由上配置 `response-rewrite`。 :::note @@ -81,175 +79,235 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ ::: +### 重写标头和正文 + +以下示例演示了如何添加响应正文和标头,仅适用于具有 `200` HTTP 状态代码的响应。 + +创建一个带有 `response-rewrite` 插件的路由: + ```shell -curl http://127.0.0.1:9180/apisix/admin/routes/1 \ --H "X-API-KEY: $admin_key" -X PUT -d ' -{ +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "response-rewrite-route", "methods": ["GET"], - "uri": "/test/index.html", + "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 ] - ] - } + "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": { - "127.0.0.1:80": 1 - } + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } } -}' + }' ``` -在上述命令中,通过配置 `vars` 参数可以让该插件仅在具有 200 状态码的响应上运行插件。 - -除了 `set` 操作,你也可以像这样增加或移除响应头: - -```json -"headers": { - "add": [ - "X-Server-balancer-addr: $balancer_ip:$balancer_port" - ], - "remove": [ - "X-TO-BE-REMOVED" - ] -} -``` - -这些操作的执行顺序为 ["add", "set", "remove"]。 - -我们不再对直接在 `headers` 下面设置响应头的方式提供支持。 -如果你的配置是把响应头设置到 `headers` 的下一层,你需要将这些配置移到 `headers.set`。 - -## 测试插件 - -通过上述命令启用插件后,可以使用如下命令测试插件是否启用成功: +发送请求以验证: ```shell -curl -X GET -i http://127.0.0.1:9080/test/index.html +curl -i "http://127.0.0.1:9080/headers" ``` -无论来自上游的响应是什么,返回结果都是相同的: +您应该收到类似于以下内容的 `HTTP/1.1 200 OK` 响应: -```shell -HTTP/1.1 200 OK -Date: Sat, 16 Nov 2019 09:15:12 GMT -Transfer-Encoding: chunked -Connection: keep-alive +```text +... X-Server-id: 3 X-Server-status: on -X-Server-balancer-addr: 127.0.0.1:80 +X-Server-balancer-addr: 50.237.103.220:80 {"code":"ok","message":"new json body"} ``` -:::info IMPORTANT - -[ngx.exit](https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/#ngxexit) 将会中断当前请求的执行并将其状态码返回给 NGINX。 - -如果你在 `access` 阶段执行了 `ngx.exit`,该操作只是中断了请求处理阶段,响应阶段仍然会处理。如果你配置了 `response-rewrite` 插件,它会强制覆盖你的响应信息(如响应代码)。 +### 使用 RegEx 过滤器重写标头 -| Phase | rewrite | access | header_filter | body_filter | -|---------------|----------|----------|---------------|-------------| -| rewrite | ngx.exit | √ | √ | √ | -| access | × | ngx.exit | √ | √ | -| header_filter | √ | √ | ngx.exit | √ | -| body_filter | √ | √ | × | ngx.exit | - -::: +以下示例演示如何使用 RegEx 过滤器匹配替换响应中的 `X-Amzn-Trace-Id`。 -使用 `filters` 正则匹配将返回 body 的 X-Amzn-Trace-Id 替换为 X-Amzn-Trace-Id-Replace。 +创建一个带有 `response-rewrite` 插件的路由: ```shell -curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d ' -{ - "plugins":{ - "response-rewrite":{ - "headers":{ - "set": { - "X-Server-id":3, - "X-Server-status":"on", - "X-Server-balancer-addr":"$balancer_ip:$balancer_port" - } - }, - "filters":[ - { - "regex":"X-Amzn-Trace-Id", - "scope":"global", - "replace":"X-Amzn-Trace-Id-Replace" - } - ], - "vars":[ - [ - "status", - "==", - 200 +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_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", - "scheme":"https", - "nodes":{ - "httpbin.org:443":1 + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } } - }, - "uri":"/*" -}' + }' ``` +发送请求以验证: + ```shell -curl -X GET -i http://127.0.0.1:9080/get +curl -i "http://127.0.0.1:9080/headers" ``` -```shell -HTTP/1.1 200 OK -Transfer-Encoding: chunked -X-Server-status: on -X-Server-balancer-addr: 34.206.80.189:443 -X-Server-id: 3 +您应该会看到类似以下内容的响应: +```text { - "args": {}, "headers": { "Accept": "*/*", "Host": "127.0.0.1", - "User-Agent": "curl/7.29.0", - "X-Amzn-Trace-Id-Replace": "Root=1-629e0b89-1e274fdd7c23ca6e64145aa2", + "User-Agent": "curl/8.2.1", + "X-Amzn-Trace-Id-Replace": "Root=1-6500095d-1041b05e2ba9c6b37232dbc7", "X-Forwarded-Host": "127.0.0.1" - }, - "origin": "127.0.0.1, 117.136.46.203", - "url": "https://127.0.0.1/get" + } } - ``` -## 删除插件 +### 从 Base64 解码正文 + +以下示例演示如何从 Base64 格式解码正文。 -当你需要禁用 `response-rewrite` 插件时,可以通过以下命令删除相应的 JSON 配置,APISIX 将会自动重新加载相关配置,无需重启服务: +创建一个带有 `response-rewrite` 插件的路由: ```shell -curl http://127.0.0.1:9180/apisix/admin/routes/1 \ --H "X-API-KEY: $admin_key" -X PUT -d ' -{ +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "response-rewrite-route", "methods": ["GET"], - "uri": "/test/index.html", - "upstream": { - "type": "roundrobin", - "nodes": { - "127.0.0.1:80": 1 + "uri": "/get", + "plugins":{ + "response-rewrite": { + "body": "SGVsbG8gV29ybGQ=", + "body_base64": true } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } } -}' + }' +``` + +发送请求以验证: + +```shell +curl "http://127.0.0.1:9080/get" +``` + +您应该看到以下响应: + +```text +Hello World ``` + +### 重写响应及其与执行阶段的联系 + +以下示例通过使用 `key-auth` 插件配置插件,演示了 `response-rewrite` 插件与 [执行阶段](/apisix/key-concepts/plugins#plugins-execution-lifecycle) 之间的联系,并查看在未经身份验证的请求的情况下,响应仍如何重写为 `200 OK`。 + +创建消费者 `jack`: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "username": "jack" + }' +``` + +为消费者创建 `key-auth` 凭证: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id": "cred-jack-key-auth", + "plugins": { + "key-auth": { + "key": "jack-key" + } + } + }' +``` + +创建一个带有 `key-auth` 的路由,并配置 `response-rewrite` 来重写响应状态码和主体: + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_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 + } + } + }' +``` + +使用有效密钥向路由发送请求: + +```shell +curl -i "http://127.0.0.1:9080/get" -H 'apikey: jack-key' +``` + +您应该收到以下 `HTTP/1.1 200 OK` 响应: + +```text +{"code": 200, "msg": "success"} +``` + +向路由发送一个没有任何键的请求: + +```shell +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** 阶段逻辑将在 [`ngx.exit`](https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/#ngxexit) 之后在其他插件的 **access** 或 **rewrite** 阶段继续运行。 + +下表总结了 `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** 阶段。