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
```