This is an automated email from the ASF dual-hosted git repository.

Yilialinn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 3f5cd10c3 docs(cors): re-port with Admin API, ADC, and Ingress 
Controller tabs (#13261)
3f5cd10c3 is described below

commit 3f5cd10c3fe21ed4ceb9e210fa1c5e5674925198
Author: Yilia Lin <[email protected]>
AuthorDate: Wed Apr 22 14:43:55 2026 +0800

    docs(cors): re-port with Admin API, ADC, and Ingress Controller tabs 
(#13261)
---
 docs/en/latest/plugins/cors.md | 812 +++++++++++++++++++++++++++++++++++++----
 docs/zh/latest/plugins/cors.md | 797 +++++++++++++++++++++++++++++++++++++---
 2 files changed, 1496 insertions(+), 113 deletions(-)

diff --git a/docs/en/latest/plugins/cors.md b/docs/en/latest/plugins/cors.md
index a5fa0d5d6..553af120c 100644
--- a/docs/en/latest/plugins/cors.md
+++ b/docs/en/latest/plugins/cors.md
@@ -4,7 +4,7 @@ keywords:
   - Apache APISIX
   - API Gateway
   - CORS
-description: This document contains information about the Apache APISIX cors 
Plugin.
+description: The cors Plugin allows you to enable Cross-Origin Resource 
Sharing (CORS).
 ---
 
 <!--
@@ -26,117 +26,801 @@ description: This document contains information about the 
Apache APISIX cors Plu
 #
 -->
 
+<head>
+  <link rel="canonical" href="https://docs.api7.ai/hub/cors"; />
+</head>
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
 ## Description
 
-The `cors` Plugins lets you enable 
[CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) easily.
+The `cors` Plugin allows you to enable [Cross-Origin Resource Sharing 
(CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). CORS is an 
HTTP-header based mechanism which allows a server to specify any origins 
(domain, scheme, or port) other than its own, and instructs browsers to allow 
the loading of resources from those origins.
 
 ## Attributes
 
-### CORS attributes
-
-| Name                      | Type    | Required | Default | Description       
                                                                                
                                                                                
                                                                                
                                                                                
                                                 |
-|---------------------------|---------|----------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| allow_origins             | string  | False    | "*"     | Origins to allow 
CORS. Use the `scheme://host:port` format. For example, 
`https://somedomain.com:8081`. If you have multiple origins, use a `,` to list 
them. If `allow_credential` is set to `false`, you can enable CORS for all 
origins by using `*`. If `allow_credential` is set to `true`, you can 
forcefully allow CORS on all origins by using `**` but it will pose some 
security issues. |
-| allow_methods             | string  | False    | "*"     | Request methods 
to enable CORS on. For example `GET`, `POST`. Use `,` to add multiple methods. 
If `allow_credential` is set to `false`, you can enable CORS for all methods by 
using `*`. If `allow_credential` is set to `true`, you can forcefully allow 
CORS on all methods by using `**` but it will pose some security issues.        
                                                        |
-| allow_headers             | string  | False    | "*"     | Headers in the 
request allowed when accessing a cross-origin resource. Use `,` to add multiple 
headers. If `allow_credential` is set to `false`, you can enable CORS for all 
request headers by using `*`. If `allow_credential` is set to `true`, you can 
forcefully allow CORS on all request headers by using `**` but it will pose 
some security issues.                                       |
-| expose_headers            | string  | False    |         | Headers in the 
response allowed when accessing a cross-origin resource. Use `,` to add 
multiple headers. If `allow_credential` is set to `false`, you can enable CORS 
for all response headers by using `*`. If not specified, the plugin will not 
modify the `Access-Control-Expose-Headers header`. See 
[Access-Control-Expose-Headers - 
MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers)
 for mo [...]
-| max_age                   | integer | False    | 5       | Maximum time in 
seconds the result is cached. If the time is within this limit, the browser 
will check the cached result. Set to `-1` to disable caching. Note that the 
maximum value is browser dependent. See 
[Access-Control-Max-Age](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#Directives)
 for more details.                                            |
-| allow_credential          | boolean | False    | false   | When set to 
`true`, allows requests to include credentials like cookies. According to CORS 
specification, if you set this to `true`, you cannot use '*' to allow all for 
the other attributes.                                                           
                                                                                
                                                          |
-| allow_origins_by_regex    | array   | False    | nil     | Regex to match 
origins that allow CORS. For example, `[".*\.test.com$"]` can match all 
subdomains of `test.com`. When set to specified range, only domains in this 
range will be allowed, no matter what `allow_origins` is.                       
                                                                                
                                                            |
-| allow_origins_by_metadata | array   | False    | nil     | Origins to enable 
CORS referenced from `allow_origins` set in the Plugin metadata. For example, 
if `"allow_origins": {"EXAMPLE": "https://example.com"}` is set in the Plugin 
metadata, then `["EXAMPLE"]` can be used to allow CORS on the origin 
`https://example.com`.                                                          
                                                                |
+| Name | Type | Required | Default | Valid values | Description |
+|---|---|---|---|---|---|
+| allow_origins | string | False | `"*"` | | Comma-separated string of origins 
to allow CORS, in the format `scheme://host:port`, for example 
`https://somedomain.com:8081`. If you have multiple origins, use `,` to list 
them. If `allow_credential` is set to `false`, you can use `*` to allow all 
origins. If `allow_credential` is set to `true`, you can use `**` to forcefully 
allow all origins, but this poses security risks. |
+| allow_methods | string | False | `"*"` | | Comma-separated string of HTTP 
request methods to allow CORS, for example `GET`, `POST`. If `allow_credential` 
is set to `false`, you can use `*` to allow all methods. If `allow_credential` 
is set to `true`, you can use `**` to forcefully allow all methods, but this 
poses security risks. |
+| allow_headers | string | False | `"*"` | | Comma-separated string of HTTP 
headers allowed in requests when accessing a cross-origin resource. If 
`allow_credential` is set to `false`, you can use `*` to allow all request 
headers. If `allow_credential` is set to `true`, you can use `**` to forcefully 
allow all request headers, but this poses security risks. |
+| expose_headers | string | False | | | Comma-separated string of HTTP headers 
that should be made available in response to a cross-origin request. If 
`allow_credential` is set to `false`, you can use `*` to allow all response 
headers. If not specified, the Plugin will not modify the 
`Access-Control-Expose-Headers` header. See [Access-Control-Expose-Headers - 
MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers)
 for more details. |
+| max_age | integer | False | 5 | | Maximum time in seconds for which the 
results of a preflight request can be cached. If the time is within this limit, 
the browser will check the cached result. Set to `-1` to disable caching. Note 
that the maximum value is browser-dependent. See 
[Access-Control-Max-Age](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#Directives)
 for more details. |
+| allow_credential | boolean | False | false | | When set to `true`, allows 
requests to include credentials such as cookies. According to CORS 
specification, if you set this to `true`, you cannot use `*` for other CORS 
attributes. |
+| allow_origins_by_regex | array | False | | | Regex to match origins that 
allow CORS. For example, `[".*\.test.com$"]` can match all subdomains of 
`test.com`. When configured, only domains matching the RegEx will be allowed 
and `allow_origins` will be ignored. |
+| allow_origins_by_metadata | array | False | | | Origins to enable CORS 
referenced from `allow_origins` set in the Plugin metadata. For example, if 
`"allow_origins": {"EXAMPLE": "https://example.com"}` is set in the Plugin 
metadata, then `["EXAMPLE"]` can be used to allow CORS on the origin 
`https://example.com`. |
+| timing_allow_origins | string | False | | | Comma-separated string of 
origins to allow access to the resource timing information. See 
[Timing-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin)
 for more details. |
+| timing_allow_origins_by_regex | array | False | | | Regex to match origins 
for enabling access to the resource timing information. For example, 
`[".*\.test.com"]` can match all subdomains of `test.com`. When configured, 
only domains matching the RegEx will be allowed and `timing_allow_origins` will 
be ignored. |
 
 :::info IMPORTANT
 
-1. The `allow_credential` attribute is sensitive and must be used carefully. 
If set to `true` the default value `*` of the other attributes will be invalid 
and they should be specified explicitly.
+1. The `allow_credential` attribute is sensitive and must be used carefully. 
If set to `true`, the default value `*` of the other attributes will be invalid 
and they should be specified explicitly.
 2. When using `**` you are vulnerable to security risks like CSRF. Make sure 
that this meets your security levels before using it.
 
 :::
 
-### Resource Timing attributes
+## Metadata
+
+| Name | Type | Required | Default | Valid values | Description |
+|---|---|---|---|---|---|
+| allow_origins | object | False | | | A map of keys and allowed origins. The 
keys are used in the `allow_origins_by_metadata` attribute and the values are 
equivalent to the `allow_origins` attribute of the Plugin. |
+
+## Examples
 
-| Name                      | Type    | Required | Default | Description       
                                                                                
                                                                                
                                                                                
                                                                                
                                                 |
-|---------------------------|---------|----------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| timing_allow_origins             | string  | False    | nil     | Origin to 
allow to access the resource timing information. See 
[Timing-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin).
 Use the `scheme://host:port` format. For example, 
`https://somedomain.com:8081`. If you have multiple origins, use a `,` to list 
them. |
-| timing_allow_origins_by_regex    | array   | False    | nil     | Regex to 
match with origin for enabling access to the resource timing information. For 
example, `[".*\.test.com"]` can match all subdomain of `test.com`. When set to 
specified range, only domains in this range will be allowed, no matter what 
`timing_allow_origins` is. |
+The examples below demonstrate how you can configure the `cors` Plugin for 
different scenarios.
 
 :::note
 
-The Timing-Allow-Origin header is defined in the Resource Timing API, but it 
is related to the CORS concept.
+You can fetch the `admin_key` from `config.yaml` and save to an environment 
variable with the following command:
 
-Suppose you have 2 domains, `domain-A.com` and `domain-B.com`.
-You are on a page on `domain-A.com`, you have an XHR call to a resource on 
`domain-B.com` and you need its timing information.
-You can allow the browser to show this timing information only if you have 
cross-origin permissions on `domain-B.com`.
-So, you have to set the CORS headers first, then access the `domain-B.com` 
URL, and if you set 
[Timing-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin),
 the browser will show the requested timing information.
+```bash
+admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 
's/"//g')
+```
 
 :::
 
-## Metadata
+### Enable CORS for a Route
 
-| Name          | Type   | Required | Description                              
                                                                                
                                                                               |
-|---------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| allow_origins | object | False    | A map with origin reference and allowed 
origins. The keys in the map are used in the attribute 
`allow_origins_by_metadata` and the value are equivalent to the `allow_origins` 
attribute of the Plugin. |
+The following example demonstrates how to enable CORS on a Route to allow 
resource loading from a list of origins.
 
-## Enable Plugin
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'},
+{label: 'Ingress Controller', value: 'aic'}
+]}>
 
-You can enable the Plugin on a specific Route or Service:
+<TabItem value="admin-api">
 
-:::note
-You can fetch the `admin_key` from `config.yaml` and save to an environment 
variable with the following command:
+Create a Route with the `cors` Plugin:
 
-```bash
-admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 
's/"//g')
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "id": "cors-route",
+    "uri": "/anything",
+    "plugins": {
+      "cors": {
+        "allow_origins": "http://sub.domain.com,http://sub2.domain.com";,
+        "allow_methods": "GET,POST",
+        "allow_headers": "headr1,headr2",
+        "expose_headers": "ex-headr1,ex-headr2",
+        "max_age": 50,
+        "allow_credential": true
+      }
+    },
+    "upstream": {
+      "nodes": {
+        "httpbin.org:80": 1
+      },
+      "type": "roundrobin"
+    }
+  }'
 ```
 
-:::
+</TabItem>
+
+<TabItem value="adc">
+
+```yaml title="adc.yaml"
+services:
+  - name: cors-service
+    routes:
+      - name: cors-route
+        uris:
+          - /anything
+        plugins:
+          cors:
+            allow_origins: "http://sub.domain.com,http://sub2.domain.com";
+            allow_methods: "GET,POST"
+            allow_headers: "headr1,headr2"
+            expose_headers: "ex-headr1,ex-headr2"
+            max_age: 50
+            allow_credential: true
+    upstream:
+      type: roundrobin
+      nodes:
+        - host: httpbin.org
+          port: 80
+          weight: 1
+```
+
+Synchronize the configuration to APISIX:
+
+```shell
+adc sync -f adc.yaml
+```
+
+</TabItem>
+
+<TabItem value="aic">
+
+<Tabs
+groupId="k8s-api"
+defaultValue="gateway-api"
+values={[
+{label: 'Gateway API', value: 'gateway-api'},
+{label: 'APISIX Ingress Controller', value: 'apisix-ingress-controller'}
+]}>
+
+<TabItem value="gateway-api">
+
+```yaml title="cors-ic.yaml"
+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: cors-plugin-config
+spec:
+  plugins:
+    - name: cors
+      config:
+        allow_origins: "http://sub.domain.com,http://sub2.domain.com";
+        allow_methods: "GET,POST"
+        allow_headers: "headr1,headr2"
+        expose_headers: "ex-headr1,ex-headr2"
+        max_age: 50
+        allow_credential: true
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  namespace: aic
+  name: cors-route
+spec:
+  parentRefs:
+    - name: apisix
+  rules:
+    - matches:
+        - path:
+            type: Exact
+            value: /anything
+      filters:
+        - type: ExtensionRef
+          extensionRef:
+            group: apisix.apache.org
+            kind: PluginConfig
+            name: cors-plugin-config
+      backendRefs:
+        - name: httpbin-external-domain
+          port: 80
+```
+
+Apply the configuration to your cluster:
 
 ```shell
-curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X 
PUT -d '
-{
-    "uri": "/hello",
+kubectl apply -f cors-ic.yaml
+```
+
+</TabItem>
+
+<TabItem value="apisix-ingress-controller">
+
+```yaml title="cors-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: cors-route
+spec:
+  ingressClassName: apisix
+  http:
+    - name: cors-route
+      match:
+        paths:
+          - /anything
+      upstreams:
+      - name: httpbin-external-domain
+      plugins:
+      - name: cors
+        enable: true
+        config:
+          allow_origins: "http://sub.domain.com,http://sub2.domain.com";
+          allow_methods: "GET,POST"
+          allow_headers: "headr1,headr2"
+          expose_headers: "ex-headr1,ex-headr2"
+          max_age: 50
+          allow_credential: true
+```
+
+Apply the configuration to your cluster:
+
+```shell
+kubectl apply -f cors-ic.yaml
+```
+
+</TabItem>
+
+</Tabs>
+
+</TabItem>
+
+</Tabs>
+
+Send a request to the Route with an allowed origin:
+
+```shell
+curl "http://127.0.0.1:9080/anything"; -H "Origin: http://sub2.domain.com"; -I
+```
+
+You should receive an `HTTP/1.1 200 OK` response and observe CORS headers:
+
+```text
+...
+Access-Control-Allow-Origin: http://sub2.domain.com
+Access-Control-Allow-Credentials: true
+Server: APISIX/3.8.0
+Vary: Origin
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Max-Age: 50
+Access-Control-Expose-Headers: ex-headr1,ex-headr2
+Access-Control-Allow-Headers: headr1,headr2
+```
+
+Send a request to the Route with an origin that is not allowed:
+
+```shell
+curl "http://127.0.0.1:9080/anything"; -H "Origin: http://sub3.domain.com"; -I
+```
+
+You should receive an `HTTP/1.1 200 OK` response without any CORS headers:
+
+```text
+...
+Server: APISIX/3.8.0
+Vary: Origin
+```
+
+### Use RegEx to Match Origin
+
+The following example demonstrates how to use a regular expression to match 
allowed origins using the `allow_origins_by_regex` attribute.
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'},
+{label: 'Ingress Controller', value: 'aic'}
+]}>
+
+<TabItem value="admin-api">
+
+Create a Route with the `cors` Plugin:
+
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "id": "cors-route",
+    "uri": "/anything",
     "plugins": {
-        "cors": {}
+      "cors": {
+        "allow_methods": "GET,POST",
+        "allow_headers": "headr1,headr2",
+        "expose_headers": "ex-headr1,ex-headr2",
+        "max_age": 50,
+        "allow_origins_by_regex": [ ".*\\.test.com$" ]
+      }
     },
     "upstream": {
-        "type": "roundrobin",
-        "nodes": {
-            "127.0.0.1:8080": 1
-        }
+      "nodes": {
+        "httpbin.org:80": 1
+      },
+      "type": "roundrobin"
     }
-}'
+  }'
 ```
 
-## Example usage
+</TabItem>
+
+<TabItem value="adc">
 
-After enabling the Plugin, you can make a request to the server and see the 
CORS headers returned:
+```yaml title="adc.yaml"
+services:
+  - name: cors-service
+    routes:
+      - name: cors-route
+        uris:
+          - /anything
+        plugins:
+          cors:
+            allow_methods: "GET,POST"
+            allow_headers: "headr1,headr2"
+            expose_headers: "ex-headr1,ex-headr2"
+            max_age: 50
+            allow_origins_by_regex:
+              - ".*\\.test.com$"
+    upstream:
+      type: roundrobin
+      nodes:
+        - host: httpbin.org
+          port: 80
+          weight: 1
+```
+
+Synchronize the configuration to APISIX:
 
 ```shell
-curl http://127.0.0.1:9080/hello -v
+adc sync -f adc.yaml
+```
+
+</TabItem>
+
+<TabItem value="aic">
+
+<Tabs
+groupId="k8s-api"
+defaultValue="gateway-api"
+values={[
+{label: 'Gateway API', value: 'gateway-api'},
+{label: 'APISIX Ingress Controller', value: 'apisix-ingress-controller'}
+]}>
+
+<TabItem value="gateway-api">
+
+```yaml title="cors-ic.yaml"
+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: cors-regex-plugin-config
+spec:
+  plugins:
+    - name: cors
+      config:
+        allow_methods: "GET,POST"
+        allow_headers: "headr1,headr2"
+        expose_headers: "ex-headr1,ex-headr2"
+        max_age: 50
+        allow_origins_by_regex:
+          - ".*\\.test.com$"
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  namespace: aic
+  name: cors-route
+spec:
+  parentRefs:
+    - name: apisix
+  rules:
+    - matches:
+        - path:
+            type: Exact
+            value: /anything
+      filters:
+        - type: ExtensionRef
+          extensionRef:
+            group: apisix.apache.org
+            kind: PluginConfig
+            name: cors-regex-plugin-config
+      backendRefs:
+        - name: httpbin-external-domain
+          port: 80
 ```
 
+Apply the configuration to your cluster:
+
 ```shell
+kubectl apply -f cors-ic.yaml
+```
+
+</TabItem>
+
+<TabItem value="apisix-ingress-controller">
+
+```yaml title="cors-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: cors-route
+spec:
+  ingressClassName: apisix
+  http:
+    - name: cors-route
+      match:
+        paths:
+          - /anything
+      upstreams:
+      - name: httpbin-external-domain
+      plugins:
+      - name: cors
+        enable: true
+        config:
+          allow_methods: "GET,POST"
+          allow_headers: "headr1,headr2"
+          expose_headers: "ex-headr1,ex-headr2"
+          max_age: 50
+          allow_origins_by_regex:
+            - ".*\\.test.com$"
+```
+
+Apply the configuration to your cluster:
+
+```shell
+kubectl apply -f cors-ic.yaml
+```
+
+</TabItem>
+
+</Tabs>
+
+</TabItem>
+
+</Tabs>
+
+Send a request to the Route with an allowed origin:
+
+```shell
+curl "http://127.0.0.1:9080/anything"; -H "Origin: http://a.test.com"; -I
+```
+
+You should receive an `HTTP/1.1 200 OK` response and observe CORS headers:
+
+```text
 ...
-< Server: APISIX web server
-< Access-Control-Allow-Origin: *
-< Access-Control-Allow-Methods: *
-< Access-Control-Allow-Headers: *
-< Access-Control-Max-Age: 5
+Access-Control-Allow-Origin: http://a.test.com
+Server: APISIX/3.8.0
+Vary: Origin
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Max-Age: 50
+Access-Control-Expose-Headers: ex-headr1,ex-headr2
+Access-Control-Allow-Headers: headr1,headr2
+```
+
+Send a request with an origin that does not match the pattern:
+
+```shell
+curl "http://127.0.0.1:9080/anything"; -H "Origin: http://a.test2.com"; -I
+```
+
+You should receive an `HTTP/1.1 200 OK` response without any CORS headers:
+
+```text
 ...
+Server: APISIX/3.8.0
+Vary: Origin
 ```
 
-## Delete Plugin
+### Configure Origins in Plugin Metadata
+
+The following example demonstrates how to configure allowed origins in [Plugin 
metadata](https://apisix.apache.org/docs/apisix/terminology/plugin/) and 
reference them in the `cors` Plugin using `allow_origins_by_metadata`.
 
-To remove the `cors` 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.
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'},
+{label: 'Ingress Controller', value: 'aic'}
+]}>
+
+<TabItem value="admin-api">
+
+Configure Plugin metadata for the `cors` Plugin:
 
 ```shell
-curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X 
PUT -d '
-{
-    "uri": "/hello",
-    "plugins": {},
+curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/cors"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "allow_origins": {
+      "key_1": "https://domain.com";,
+      "key_2": "https://sub.domain.com,https://sub2.domain.com";,
+      "key_3": "*"
+    }
+  }'
+```
+
+Create a Route with the `cors` Plugin using `allow_origins_by_metadata`:
+
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "id": "cors-route",
+    "uri": "/anything",
+    "plugins": {
+      "cors": {
+        "allow_methods": "GET,POST",
+        "allow_headers": "headr1,headr2",
+        "expose_headers": "ex-headr1,ex-headr2",
+        "max_age": 50,
+        "allow_origins_by_metadata": ["key_1"]
+      }
+    },
     "upstream": {
-        "type": "roundrobin",
-        "nodes": {
-            "127.0.0.1:8080": 1
-        }
+      "nodes": {
+        "httpbin.org:80": 1
+      },
+      "type": "roundrobin"
     }
-}'
+  }'
+```
+
+</TabItem>
+
+<TabItem value="adc">
+
+```yaml title="adc.yaml"
+plugin_metadata:
+  cors:
+    allow_origins:
+      key_1: "https://domain.com";
+      key_2: "https://sub.domain.com,https://sub2.domain.com";
+      key_3: "*"
+services:
+  - name: cors-service
+    routes:
+      - name: cors-route
+        uris:
+          - /anything
+        plugins:
+          cors:
+            allow_methods: "GET,POST"
+            allow_headers: "headr1,headr2"
+            expose_headers: "ex-headr1,ex-headr2"
+            max_age: 50
+            allow_origins_by_metadata:
+              - "key_1"
+    upstream:
+      type: roundrobin
+      nodes:
+        - host: httpbin.org
+          port: 80
+          weight: 1
+```
+
+Synchronize the configuration to APISIX:
+
+```shell
+adc sync -f adc.yaml
+```
+
+</TabItem>
+
+<TabItem value="aic">
+
+Update your GatewayProxy manifest to configure the Plugin metadata:
+
+```yaml title="gatewayproxy.yaml"
+apiVersion: apisix.apache.org/v1alpha1
+kind: GatewayProxy
+metadata:
+  namespace: aic
+  name: apisix-config
+spec:
+  provider:
+    type: ControlPlane
+    controlPlane:
+      # your control plane connection configuration
+  pluginMetadata:
+    cors:
+      allow_origins:
+        key_1: "https://domain.com";
+        key_2: "https://sub.domain.com,https://sub2.domain.com";
+        key_3: "*"
+```
+
+<Tabs
+groupId="k8s-api"
+defaultValue="gateway-api"
+values={[
+{label: 'Gateway API', value: 'gateway-api'},
+{label: 'APISIX Ingress Controller', value: 'apisix-ingress-controller'}
+]}>
+
+<TabItem value="gateway-api">
+
+Create the Route with `allow_origins_by_metadata`:
+
+```yaml title="cors-ic.yaml"
+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: cors-metadata-plugin-config
+spec:
+  plugins:
+    - name: cors
+      config:
+        allow_methods: "GET,POST"
+        allow_headers: "headr1,headr2"
+        expose_headers: "ex-headr1,ex-headr2"
+        max_age: 50
+        allow_origins_by_metadata:
+          - "key_1"
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  namespace: aic
+  name: cors-route
+spec:
+  parentRefs:
+    - name: apisix
+  rules:
+    - matches:
+        - path:
+            type: Exact
+            value: /anything
+      filters:
+        - type: ExtensionRef
+          extensionRef:
+            group: apisix.apache.org
+            kind: PluginConfig
+            name: cors-metadata-plugin-config
+      backendRefs:
+        - name: httpbin-external-domain
+          port: 80
+```
+
+Apply the configuration to your cluster:
+
+```shell
+kubectl apply -f gatewayproxy.yaml -f cors-ic.yaml
+```
+
+</TabItem>
+
+<TabItem value="apisix-ingress-controller">
+
+Create the Route with `allow_origins_by_metadata`:
+
+```yaml title="cors-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: cors-route
+spec:
+  ingressClassName: apisix
+  http:
+    - name: cors-route
+      match:
+        paths:
+          - /anything
+      upstreams:
+      - name: httpbin-external-domain
+      plugins:
+      - name: cors
+        enable: true
+        config:
+          allow_methods: "GET,POST"
+          allow_headers: "headr1,headr2"
+          expose_headers: "ex-headr1,ex-headr2"
+          max_age: 50
+          allow_origins_by_metadata:
+            - "key_1"
+```
+
+Apply the configuration to your cluster:
+
+```shell
+kubectl apply -f gatewayproxy.yaml -f cors-ic.yaml
+```
+
+</TabItem>
+
+</Tabs>
+
+</TabItem>
+
+</Tabs>
+
+Send a request to the Route with an allowed origin:
+
+```shell
+curl "http://127.0.0.1:9080/anything"; -H "Origin: https://domain.com"; -I
+```
+
+You should receive an `HTTP/1.1 200 OK` response and observe CORS headers:
+
+```text
+...
+Access-Control-Allow-Origin: https://domain.com
+Server: APISIX/3.8.0
+Vary: Origin
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Max-Age: 50
+Access-Control-Expose-Headers: ex-headr1,ex-headr2
+Access-Control-Allow-Headers: headr1,headr2
+```
+
+Send a request with an origin not in the metadata:
+
+```shell
+curl "http://127.0.0.1:9080/anything"; -H "Origin: http://a.test2.com"; -I
+```
+
+You should receive an `HTTP/1.1 200 OK` response without any CORS headers:
+
+```text
+...
+Server: APISIX/3.8.0
+Vary: Origin
 ```
diff --git a/docs/zh/latest/plugins/cors.md b/docs/zh/latest/plugins/cors.md
index 9367c2756..890390db7 100644
--- a/docs/zh/latest/plugins/cors.md
+++ b/docs/zh/latest/plugins/cors.md
@@ -4,7 +4,7 @@ keywords:
   - Apache APISIX
   - API 网关
   - CORS
-description: 本文介绍了 Apache APISIX cors 插件的基本信息及使用方法。
+description: cors 插件允许你启用跨域资源共享 (CORS,Cross-Origin Resource Sharing)。
 ---
 
 <!--
@@ -26,22 +26,31 @@ description: 本文介绍了 Apache APISIX cors 插件的基本信息及使用
 #
 -->
 
+<head>
+  <link rel="canonical" href="https://docs.api7.ai/hub/cors"; />
+</head>
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
 ## 描述
 
-`cors` 插件可以让你轻松地为服务端启用 
[CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)(Cross-Origin 
Resource Sharing,跨域资源共享)的返回头。
+`cors` 插件允许你启用[跨域资源共享 (CORS,Cross-Origin Resource 
Sharing)](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Guides/CORS)。CORS 
是一种基于 HTTP 头的机制,它允许服务器指定除自身以外的任意源(域、协议或端口),并指示浏览器允许从这些源加载资源。
 
 ## 属性
 
-| 名称             | 类型    | 必选项 | 默认值 | 描述                                      
                   |
-| ---------------- | ------- | ------ | ------ | 
------------------------------------------------------------ |
-| allow_origins    | string  | 否   | "*"    | 允许跨域访问的 Origin,格式为 
`scheme://host:port`,示例如 `https://somedomain.com:8081`。如果你有多个 Origin,请使用 `,` 
分隔。当 `allow_credential` 为 `false` 时,可以使用 `*` 来表示允许所有 Origin 通过。你也可以在启用了 
`allow_credential` 后使用 `**` 强制允许所有 Origin 均通过,但请注意这样存在安全隐患。 |
-| allow_methods    | string  | 否   | "*"    | 允许跨域访问的 Method,比如:`GET`,`POST` 
等。如果你有多个 Method,请使用 `,` 分割。当 `allow_credential` 为 `false` 时,可以使用 `*` 来表示允许所有 
Method 通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有 Method 都通过,但请注意这样存在安全隐患。 |
-| allow_headers    | string  | 否   | "*"    | 允许跨域访问时请求方携带哪些非 `CORS 规范` 以外的 
Header。如果你有多个 Header,请使用 `,` 分割。当 `allow_credential` 为 `false` 时,可以使用 `*` 
来表示允许所有 Header 通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有 Header 
都通过,但请注意这样存在安全隐患。 |
-| expose_headers   | string  | 否   |        | 允许跨域访问时响应方携带哪些非 CORS 规范 以外的 
Header。如果你有多个 Header,请使用 , 分割。当 allow_credential 为 false 时,可以使用 * 来表示允许任意 
Header。如果不设置,插件不会修改 `Access-Control-Expose-Headers` 头,详情请参考 
[Access-Control-Expose-Headers - 
MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers)。
 |
-| max_age          | integer | 否   | 5      | 浏览器缓存 CORS 
结果的最大时间,单位为秒。在这个时间范围内,浏览器会复用上一次的检查结果,`-1` 表示不缓存。请注意各个浏览器允许的最大时间不同,详情请参考 
[Access-Control-Max-Age - 
MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#directives)。
 |
-| allow_credential | boolean | 否   | false  | 是否允许跨域访问的请求方携带凭据(如 Cookie 等)。根据 
CORS 规范,如果设置该选项为 `true`,那么将不能在其他属性中使用 `*`。 |
-| allow_origins_by_regex | array | 否   | nil  | 使用正则表达式数组来匹配允许跨域访问的 Origin,如 
`[".*\.test.com$"]` 可以匹配任何 `test.com` 的子域名。如果 `allow_origins_by_regex` 
属性已经指定,则会忽略 `allow_origins` 属性。 |
-| allow_origins_by_metadata | array | 否    | nil   | 通过引用插件元数据的 
`allow_origins` 配置允许跨域访问的 Origin。比如当插件元数据为 `"allow_origins": {"EXAMPLE": 
"https://example.com"}` 时,配置 `["EXAMPLE"]` 将允许 Origin `https://example.com` 
的访问。  |
+| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
+|---|---|---|---|---|---|
+| allow_origins | string | 否 | `"*"` | | 允许跨域访问的 Origin,格式为 
`scheme://host:port`,示例如 `https://somedomain.com:8081`。如果有多个 Origin,请使用 `,` 
分隔。当 `allow_credential` 为 `false` 时,可以使用 `*` 表示允许所有 Origin 通过。开启 
`allow_credential` 后可使用 `**` 强制允许所有 Origin,但存在安全隐患。 |
+| allow_methods | string | 否 | `"*"` | | 允许跨域访问的 HTTP 请求方法,比如 
`GET`、`POST`。如果有多个方法,请使用 `,` 分隔。当 `allow_credential` 为 `false` 时,可以使用 `*` 
表示允许所有方法通过。开启 `allow_credential` 后可使用 `**` 强制允许所有方法,但存在安全隐患。 |
+| allow_headers | string | 否 | `"*"` | | 允许跨域访问时请求方携带哪些非 CORS 规范以外的 
Header。如果有多个 Header,请使用 `,` 分隔。当 `allow_credential` 为 `false` 时,可以使用 `*` 表示允许所有 
Header 通过。开启 `allow_credential` 后可使用 `**` 强制允许所有 Header,但存在安全隐患。 |
+| expose_headers | string | 否 | | | 允许跨域访问时响应方携带哪些非 CORS 规范以外的 Header。如果有多个 
Header,请使用 `,` 分隔。当 `allow_credential` 为 `false` 时,可以使用 `*` 表示允许任意 
Header。如果不设置,插件不会修改 `Access-Control-Expose-Headers` 头,详情请参考 
[Access-Control-Expose-Headers - 
MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers)。
 |
+| max_age | integer | 否 | 5 | | 浏览器缓存 CORS 
预检请求结果的最大时间,单位为秒。在此时间范围内,浏览器会复用上一次的检查结果。设置为 `-1` 表示禁用缓存。请注意各浏览器允许的最大时间不同,详情请参考 
[Access-Control-Max-Age - 
MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#directives)。
 |
+| allow_credential | boolean | 否 | false | | 是否允许跨域访问的请求方携带凭据(如 Cookie 等)。根据 
CORS 规范,如果设置该选项为 `true`,那么将不能在其他属性中使用 `*`。 |
+| allow_origins_by_regex | array | 否 | | | 使用正则表达式匹配允许跨域访问的 Origin,如 
`[".*\.test.com$"]` 可以匹配 `test.com` 的所有子域名。配置后,仅匹配正则表达式的域名会被允许,`allow_origins` 
的配置将被忽略。 |
+| allow_origins_by_metadata | array | 否 | | | 通过引用插件元数据的 `allow_origins` 
配置允许跨域访问的 Origin。比如当插件元数据为 `"allow_origins": {"EXAMPLE": 
"https://example.com"}` 时,配置 `["EXAMPLE"]` 将允许 Origin `https://example.com` 
的访问。 |
+| timing_allow_origins | string | 否 | | | 允许访问资源时序信息的 Origin 列表,多个 Origin 使用 
`,` 分隔。详情请参考 
[Timing-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin)。
 |
+| timing_allow_origins_by_regex | array | 否 | | | 使用正则表达式匹配允许访问资源时序信息的 
Origin,如 `[".*\.test.com"]` 可以匹配 `test.com` 
的所有子域名。配置后,仅匹配正则表达式的域名会被允许,`timing_allow_origins` 的配置将被忽略。 |
 
 :::info IMPORTANT
 
@@ -52,19 +61,17 @@ description: 本文介绍了 Apache APISIX cors 插件的基本信息及使用
 
 ## 元数据
 
-| 名称           | 类型    | 必选项  | 描述                       |
-| -----------   | ------  | ------ | ------------------ |
-| allow_origins | object  | 否    | 定义允许跨域访问的 Origin;它的键为 
`allow_origins_by_metadata` 使用的引用键,值则为允许跨域访问的 Origin,其语义与属性中的 `allow_origins` 
相同。 |
-
-## 启用插件
+| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
+|---|---|---|---|---|---|
+| allow_origins | object | 否 | | | 定义允许跨域访问的 Origin 映射表;其键为 
`allow_origins_by_metadata` 使用的引用键,值则为允许跨域访问的 Origin,其语义与属性中的 `allow_origins` 
相同。 |
 
-你可以在路由或服务上启用 `cors` 插件。
+## 示例
 
-你可以通过如下命令在指定路由上启用 `cors` 插件:
+以下示例展示了如何针对不同场景配置 `cors` 插件。
 
 :::note
 
-您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
+你可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量:
 
 ```bash
 admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 
's/"//g')
@@ -72,56 +79,748 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' 
conf/config.yaml | sed 's/"/
 
 :::
 
+### 为路由启用 CORS
+
+以下示例展示如何在路由上启用 CORS,允许来自指定 Origin 列表的资源加载。
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'},
+{label: 'Ingress Controller', value: 'aic'}
+]}>
+
+<TabItem value="admin-api">
+
+创建带有 `cors` 插件的路由:
+
 ```shell
-curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X 
PUT -d '
-{
-    "uri": "/hello",
+curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "id": "cors-route",
+    "uri": "/anything",
     "plugins": {
-        "cors": {}
+      "cors": {
+        "allow_origins": "http://sub.domain.com,http://sub2.domain.com";,
+        "allow_methods": "GET,POST",
+        "allow_headers": "headr1,headr2",
+        "expose_headers": "ex-headr1,ex-headr2",
+        "max_age": 50,
+        "allow_credential": true
+      }
     },
     "upstream": {
-        "type": "roundrobin",
-        "nodes": {
-            "127.0.0.1:8080": 1
-        }
+      "nodes": {
+        "httpbin.org:80": 1
+      },
+      "type": "roundrobin"
     }
-}'
+  }'
 ```
 
-## 测试插件
+</TabItem>
+
+<TabItem value="adc">
+
+```yaml title="adc.yaml"
+services:
+  - name: cors-service
+    routes:
+      - name: cors-route
+        uris:
+          - /anything
+        plugins:
+          cors:
+            allow_origins: "http://sub.domain.com,http://sub2.domain.com";
+            allow_methods: "GET,POST"
+            allow_headers: "headr1,headr2"
+            expose_headers: "ex-headr1,ex-headr2"
+            max_age: 50
+            allow_credential: true
+    upstream:
+      type: roundrobin
+      nodes:
+        - host: httpbin.org
+          port: 80
+          weight: 1
+```
 
-通过上述命令启用插件后,可以使用如下命令测试插件是否启用成功:
+将配置同步至 APISIX:
 
 ```shell
-curl http://127.0.0.1:9080/hello -v
+adc sync -f adc.yaml
 ```
 
-如果返回结果中出现 CORS 相关的 header,则代表插件生效:
+</TabItem>
+
+<TabItem value="aic">
+
+<Tabs
+groupId="k8s-api"
+defaultValue="gateway-api"
+values={[
+{label: 'Gateway API', value: 'gateway-api'},
+{label: 'APISIX Ingress Controller', value: 'apisix-ingress-controller'}
+]}>
+
+<TabItem value="gateway-api">
+
+```yaml title="cors-ic.yaml"
+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: cors-plugin-config
+spec:
+  plugins:
+    - name: cors
+      config:
+        allow_origins: "http://sub.domain.com,http://sub2.domain.com";
+        allow_methods: "GET,POST"
+        allow_headers: "headr1,headr2"
+        expose_headers: "ex-headr1,ex-headr2"
+        max_age: 50
+        allow_credential: true
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  namespace: aic
+  name: cors-route
+spec:
+  parentRefs:
+    - name: apisix
+  rules:
+    - matches:
+        - path:
+            type: Exact
+            value: /anything
+      filters:
+        - type: ExtensionRef
+          extensionRef:
+            group: apisix.apache.org
+            kind: PluginConfig
+            name: cors-plugin-config
+      backendRefs:
+        - name: httpbin-external-domain
+          port: 80
+```
+
+将配置应用到集群:
 
 ```shell
+kubectl apply -f cors-ic.yaml
+```
+
+</TabItem>
+
+<TabItem value="apisix-ingress-controller">
+
+```yaml title="cors-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: cors-route
+spec:
+  ingressClassName: apisix
+  http:
+    - name: cors-route
+      match:
+        paths:
+          - /anything
+      upstreams:
+      - name: httpbin-external-domain
+      plugins:
+      - name: cors
+        enable: true
+        config:
+          allow_origins: "http://sub.domain.com,http://sub2.domain.com";
+          allow_methods: "GET,POST"
+          allow_headers: "headr1,headr2"
+          expose_headers: "ex-headr1,ex-headr2"
+          max_age: 50
+          allow_credential: true
+```
+
+将配置应用到集群:
+
+```shell
+kubectl apply -f cors-ic.yaml
+```
+
+</TabItem>
+
+</Tabs>
+
+</TabItem>
+
+</Tabs>
+
+向路由发送一个来自允许的 Origin 的请求:
+
+```shell
+curl "http://127.0.0.1:9080/anything"; -H "Origin: http://sub2.domain.com"; -I
+```
+
+你应该会收到 `HTTP/1.1 200 OK` 响应,并能看到 CORS 相关 Header:
+
+```text
 ...
-< Server: APISIX web server
-< Access-Control-Allow-Origin: *
-< Access-Control-Allow-Methods: *
-< Access-Control-Allow-Headers: *
-< Access-Control-Max-Age: 5
+Access-Control-Allow-Origin: http://sub2.domain.com
+Access-Control-Allow-Credentials: true
+Server: APISIX/3.8.0
+Vary: Origin
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Max-Age: 50
+Access-Control-Expose-Headers: ex-headr1,ex-headr2
+Access-Control-Allow-Headers: headr1,headr2
+```
+
+向路由发送一个来自不被允许的 Origin 的请求:
+
+```shell
+curl "http://127.0.0.1:9080/anything"; -H "Origin: http://sub3.domain.com"; -I
+```
+
+你应该会收到 `HTTP/1.1 200 OK` 响应,但不含任何 CORS Header:
+
+```text
 ...
+Server: APISIX/3.8.0
+Vary: Origin
 ```
 
-## 删除插件
+### 使用正则表达式匹配 Origin
+
+以下示例展示如何使用 `allow_origins_by_regex` 属性,通过正则表达式匹配允许的 Origin。
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'},
+{label: 'Ingress Controller', value: 'aic'}
+]}>
+
+<TabItem value="admin-api">
 
-当你需要禁用 `cors` 插件时,可以通过以下命令删除相应的 JSON 配置,APISIX 将会自动重新加载相关配置,无需重启服务:
+创建带有 `cors` 插件的路由:
 
 ```shell
-curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X 
PUT -d '
-{
-    "uri": "/hello",
-    "plugins": {},
+curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "id": "cors-route",
+    "uri": "/anything",
+    "plugins": {
+      "cors": {
+        "allow_methods": "GET,POST",
+        "allow_headers": "headr1,headr2",
+        "expose_headers": "ex-headr1,ex-headr2",
+        "max_age": 50,
+        "allow_origins_by_regex": [ ".*\\.test.com$" ]
+      }
+    },
     "upstream": {
-        "type": "roundrobin",
-        "nodes": {
-            "127.0.0.1:8080": 1
-        }
+      "nodes": {
+        "httpbin.org:80": 1
+      },
+      "type": "roundrobin"
     }
-}'
+  }'
+```
+
+</TabItem>
+
+<TabItem value="adc">
+
+```yaml title="adc.yaml"
+services:
+  - name: cors-service
+    routes:
+      - name: cors-route
+        uris:
+          - /anything
+        plugins:
+          cors:
+            allow_methods: "GET,POST"
+            allow_headers: "headr1,headr2"
+            expose_headers: "ex-headr1,ex-headr2"
+            max_age: 50
+            allow_origins_by_regex:
+              - ".*\\.test.com$"
+    upstream:
+      type: roundrobin
+      nodes:
+        - host: httpbin.org
+          port: 80
+          weight: 1
+```
+
+将配置同步至 APISIX:
+
+```shell
+adc sync -f adc.yaml
+```
+
+</TabItem>
+
+<TabItem value="aic">
+
+<Tabs
+groupId="k8s-api"
+defaultValue="gateway-api"
+values={[
+{label: 'Gateway API', value: 'gateway-api'},
+{label: 'APISIX Ingress Controller', value: 'apisix-ingress-controller'}
+]}>
+
+<TabItem value="gateway-api">
+
+```yaml title="cors-ic.yaml"
+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: cors-regex-plugin-config
+spec:
+  plugins:
+    - name: cors
+      config:
+        allow_methods: "GET,POST"
+        allow_headers: "headr1,headr2"
+        expose_headers: "ex-headr1,ex-headr2"
+        max_age: 50
+        allow_origins_by_regex:
+          - ".*\\.test.com$"
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  namespace: aic
+  name: cors-route
+spec:
+  parentRefs:
+    - name: apisix
+  rules:
+    - matches:
+        - path:
+            type: Exact
+            value: /anything
+      filters:
+        - type: ExtensionRef
+          extensionRef:
+            group: apisix.apache.org
+            kind: PluginConfig
+            name: cors-regex-plugin-config
+      backendRefs:
+        - name: httpbin-external-domain
+          port: 80
+```
+
+将配置应用到集群:
+
+```shell
+kubectl apply -f cors-ic.yaml
+```
+
+</TabItem>
+
+<TabItem value="apisix-ingress-controller">
+
+```yaml title="cors-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: cors-route
+spec:
+  ingressClassName: apisix
+  http:
+    - name: cors-route
+      match:
+        paths:
+          - /anything
+      upstreams:
+      - name: httpbin-external-domain
+      plugins:
+      - name: cors
+        enable: true
+        config:
+          allow_methods: "GET,POST"
+          allow_headers: "headr1,headr2"
+          expose_headers: "ex-headr1,ex-headr2"
+          max_age: 50
+          allow_origins_by_regex:
+            - ".*\\.test.com$"
+```
+
+将配置应用到集群:
+
+```shell
+kubectl apply -f cors-ic.yaml
+```
+
+</TabItem>
+
+</Tabs>
+
+</TabItem>
+
+</Tabs>
+
+向路由发送一个来自匹配的 Origin 的请求:
+
+```shell
+curl "http://127.0.0.1:9080/anything"; -H "Origin: http://a.test.com"; -I
+```
+
+你应该会收到 `HTTP/1.1 200 OK` 响应,并能看到 CORS 相关 Header:
+
+```text
+...
+Access-Control-Allow-Origin: http://a.test.com
+Server: APISIX/3.8.0
+Vary: Origin
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Max-Age: 50
+Access-Control-Expose-Headers: ex-headr1,ex-headr2
+Access-Control-Allow-Headers: headr1,headr2
+```
+
+向路由发送一个来自不匹配的 Origin 的请求:
+
+```shell
+curl "http://127.0.0.1:9080/anything"; -H "Origin: http://a.test2.com"; -I
+```
+
+你应该会收到 `HTTP/1.1 200 OK` 响应,但不含任何 CORS Header:
+
+```text
+...
+Server: APISIX/3.8.0
+Vary: Origin
+```
+
+### 在插件元数据中配置 Origin
+
+以下示例展示如何在[插件元数据](https://apisix.apache.org/zh/docs/apisix/terminology/plugin/)中配置允许的
 Origin,并通过 `allow_origins_by_metadata` 在 `cors` 插件中引用。
+
+<Tabs
+groupId="api"
+defaultValue="admin-api"
+values={[
+{label: 'Admin API', value: 'admin-api'},
+{label: 'ADC', value: 'adc'},
+{label: 'Ingress Controller', value: 'aic'}
+]}>
+
+<TabItem value="admin-api">
+
+配置 `cors` 插件的元数据:
+
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/cors"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "allow_origins": {
+      "key_1": "https://domain.com";,
+      "key_2": "https://sub.domain.com,https://sub2.domain.com";,
+      "key_3": "*"
+    }
+  }'
+```
+
+使用 `allow_origins_by_metadata` 创建带有 `cors` 插件的路由:
+
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
+  -H "X-API-KEY: ${admin_key}" \
+  -d '{
+    "id": "cors-route",
+    "uri": "/anything",
+    "plugins": {
+      "cors": {
+        "allow_methods": "GET,POST",
+        "allow_headers": "headr1,headr2",
+        "expose_headers": "ex-headr1,ex-headr2",
+        "max_age": 50,
+        "allow_origins_by_metadata": ["key_1"]
+      }
+    },
+    "upstream": {
+      "nodes": {
+        "httpbin.org:80": 1
+      },
+      "type": "roundrobin"
+    }
+  }'
+```
+
+</TabItem>
+
+<TabItem value="adc">
+
+```yaml title="adc.yaml"
+plugin_metadata:
+  cors:
+    allow_origins:
+      key_1: "https://domain.com";
+      key_2: "https://sub.domain.com,https://sub2.domain.com";
+      key_3: "*"
+services:
+  - name: cors-service
+    routes:
+      - name: cors-route
+        uris:
+          - /anything
+        plugins:
+          cors:
+            allow_methods: "GET,POST"
+            allow_headers: "headr1,headr2"
+            expose_headers: "ex-headr1,ex-headr2"
+            max_age: 50
+            allow_origins_by_metadata:
+              - "key_1"
+    upstream:
+      type: roundrobin
+      nodes:
+        - host: httpbin.org
+          port: 80
+          weight: 1
+```
+
+将配置同步至 APISIX:
+
+```shell
+adc sync -f adc.yaml
+```
+
+</TabItem>
+
+<TabItem value="aic">
+
+更新 GatewayProxy 清单以配置插件元数据:
+
+```yaml title="gatewayproxy.yaml"
+apiVersion: apisix.apache.org/v1alpha1
+kind: GatewayProxy
+metadata:
+  namespace: aic
+  name: apisix-config
+spec:
+  provider:
+    type: ControlPlane
+    controlPlane:
+      # 你的控制面连接配置
+  pluginMetadata:
+    cors:
+      allow_origins:
+        key_1: "https://domain.com";
+        key_2: "https://sub.domain.com,https://sub2.domain.com";
+        key_3: "*"
+```
+
+<Tabs
+groupId="k8s-api"
+defaultValue="gateway-api"
+values={[
+{label: 'Gateway API', value: 'gateway-api'},
+{label: 'APISIX Ingress Controller', value: 'apisix-ingress-controller'}
+]}>
+
+<TabItem value="gateway-api">
+
+使用 `allow_origins_by_metadata` 创建路由:
+
+```yaml title="cors-ic.yaml"
+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: cors-metadata-plugin-config
+spec:
+  plugins:
+    - name: cors
+      config:
+        allow_methods: "GET,POST"
+        allow_headers: "headr1,headr2"
+        expose_headers: "ex-headr1,ex-headr2"
+        max_age: 50
+        allow_origins_by_metadata:
+          - "key_1"
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  namespace: aic
+  name: cors-route
+spec:
+  parentRefs:
+    - name: apisix
+  rules:
+    - matches:
+        - path:
+            type: Exact
+            value: /anything
+      filters:
+        - type: ExtensionRef
+          extensionRef:
+            group: apisix.apache.org
+            kind: PluginConfig
+            name: cors-metadata-plugin-config
+      backendRefs:
+        - name: httpbin-external-domain
+          port: 80
+```
+
+将配置应用到集群:
+
+```shell
+kubectl apply -f gatewayproxy.yaml -f cors-ic.yaml
+```
+
+</TabItem>
+
+<TabItem value="apisix-ingress-controller">
+
+使用 `allow_origins_by_metadata` 创建路由:
+
+```yaml title="cors-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: cors-route
+spec:
+  ingressClassName: apisix
+  http:
+    - name: cors-route
+      match:
+        paths:
+          - /anything
+      upstreams:
+      - name: httpbin-external-domain
+      plugins:
+      - name: cors
+        enable: true
+        config:
+          allow_methods: "GET,POST"
+          allow_headers: "headr1,headr2"
+          expose_headers: "ex-headr1,ex-headr2"
+          max_age: 50
+          allow_origins_by_metadata:
+            - "key_1"
+```
+
+将配置应用到集群:
+
+```shell
+kubectl apply -f gatewayproxy.yaml -f cors-ic.yaml
+```
+
+</TabItem>
+
+</Tabs>
+
+</TabItem>
+
+</Tabs>
+
+向路由发送一个来自元数据中允许的 Origin 的请求:
+
+```shell
+curl "http://127.0.0.1:9080/anything"; -H "Origin: https://domain.com"; -I
+```
+
+你应该会收到 `HTTP/1.1 200 OK` 响应,并能看到 CORS 相关 Header:
+
+```text
+...
+Access-Control-Allow-Origin: https://domain.com
+Server: APISIX/3.8.0
+Vary: Origin
+Access-Control-Allow-Methods: GET,POST
+Access-Control-Max-Age: 50
+Access-Control-Expose-Headers: ex-headr1,ex-headr2
+Access-Control-Allow-Headers: headr1,headr2
+```
+
+向路由发送一个不在元数据中的 Origin 的请求:
+
+```shell
+curl "http://127.0.0.1:9080/anything"; -H "Origin: http://a.test2.com"; -I
+```
+
+你应该会收到 `HTTP/1.1 200 OK` 响应,但不含任何 CORS Header:
+
+```text
+...
+Server: APISIX/3.8.0
+Vary: Origin
 ```

Reply via email to