

# 针对 API Gateway 中的 REST API 的 CORS
<a name="how-to-cors"></a>

[跨源资源共享 (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) 是一项浏览器安全特征，该特征限制从在浏览器中运行的脚本启动的跨源 HTTP 请求。有关更多信息，请参阅[什么是 CORS？](https://aws.amazon.com/what-is/cross-origin-resource-sharing/)。

## 确定是否启用 CORS 支持
<a name="apigateway-cors-request-types"></a>

*跨源* HTTP 请求将向以下项发出：
+ 一个不同的*域*（例如，从 `example.com` 到 `amazondomains.com`）
+ 一个不同的*子域*（例如，从 `example.com` 到 `petstore.example.com`）
+ 一个不同的*端口*（例如，从 `example.com` 到 `example.com:10777`）
+ 一个不同的*协议*（例如，从 `https://example.com` 到 `http://example.com`）

 如果您无法访问自己的 API 并收到包含 `Cross-Origin Request Blocked` 的错误消息，则可能需要启用 CORS。

跨源 HTTP 请求可分为两种类型：*简单* 请求和*非简单* 请求。

## 为简单请求启用 CORS
<a name="apigateway-cors-simple-request"></a>

如果满足以下所有条件，则 HTTP 请求为*简单* 请求：
+ 其针对仅允许 `GET`、`HEAD` 和 `POST` 请求的 API 资源发出。
+ 如果它是一个 `POST` 方法请求，则它必须包含 `Origin` 标头。
+ 请求负载内容类型为 `text/plain`、`multipart/form-data` 或 `application/x-www-form-urlencoded`。
+ 请求不包含自定义标头。
+ [简单请求的 Mozilla CORS 文档](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests)中列出的任何其他要求。

对于简单的跨源 `POST` 方法请求，来自资源的响应需要包含标头 `Access-Control-Allow-Origin: '*'` 或 `Access-Control-Allow-Origin:'origin'`。

所有其他跨源 HTTP 请求均为*非简单* 请求。

## 为非简单请求启用 CORS
<a name="apigateway-enable-cors-non-simple"></a>

如果 API 的资源收到非简单请求，则必须根据集成类型启用额外的 CORS 支持。

### 为非代理集成启用 CORS
<a name="apigateway-enable-cors-mock"></a>

对于这些集成，[CORS 协议](https://fetch.spec.whatwg.org/#http-cors-protocol)要求浏览器在发送实际请求之前向服务器发送一个预检请求，并等待来自服务器的批准（或对于凭证的请求）。您必须配置您的 API 以向预检请求发送适当的响应。

 要创建预检响应，请执行以下操作：

1. 使用模拟集成创建 `OPTIONS` 方法。

1. 将以下响应标头添加到 200 方法响应中：
   + `Access-Control-Allow-Headers`
   + `Access-Control-Allow-Methods`
   + `Access-Control-Allow-Origin`

1. 将集成传递行为设置为 `NEVER`。在这种情况下，将拒绝未映射内容类型的方法请求，并返回“HTTP 415 不支持的媒体类型”响应。有关更多信息，请参阅[API Gateway 中适用于 REST API 且无映射模板的有效载荷的方法请求行为](integration-passthrough-behaviors.md)。

1. 输入响应标头的值。要允许所有来源、所有方法和通用标头，请使用以下标头值：
   + `Access-Control-Allow-Headers: 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'`
   + `Access-Control-Allow-Methods: 'DELETE,GET,HEAD,OPTIONS,PUT,POST,PATCH'`
   + `Access-Control-Allow-Origin: '*'`

创建预检请求后，对于至少所有 200 响应，必须为所有启用 CORS 的方法返回 `Access-Control-Allow-Origin: '*'` 或 `Access-Control-Allow-Origin:'origin'` 标头。

### 使用 AWS 管理控制台为非代理集成启用 CORS
<a name="apigateway-enable-cors-mock-console"></a>

您可以使用 AWS 管理控制台来启用 CORS。API Gateway 会创建 `OPTIONS` 方法，并尝试将 `Access-Control-Allow-Origin` 标头添加到现有的方法集成响应中。这并不总是有效，有时您需要手动修改集成响应，以便为至少所有 200 响应的所有启用 CORS 的方法返回 `Access-Control-Allow-Origin` 标头。

如果 API 的二进制媒体类型设置为 `*/*`，则当 API Gateway 创建 `OPTIONS` 方法时，请将 `contentHandling` 更改为 `CONVERT_TO_TEXT`。

以下 [update-integration](https://docs.aws.amazon.com/cli/latest/reference/apigateway/update-integration.html) 命令将集成请求的 `contentHandling` 更改为 `CONVERT_TO_TEXT`：

```
aws apigateway update-integration \
  --rest-api-id abc123 \
  --resource-id aaa111 \
  --http-method OPTIONS \
  --patch-operations op='replace',path='/contentHandling',value='CONVERT_TO_TEXT'
```

以下 [update-integration-response](https://docs.aws.amazon.com/cli/latest/reference/apigateway/update-integration-response.html) 命令将集成响应的 `contentHandling` 更改为 `CONVERT_TO_TEXT`：

```
aws apigateway update-integration-response \
  --rest-api-id abc123 \
  --resource-id aaa111 \
  --http-method OPTIONS \
  --status-code 200 \
  --patch-operations op='replace',path='/contentHandling',value='CONVERT_TO_TEXT'
```

## 为代理集成启用 CORS 支持
<a name="apigateway-enable-cors-proxy"></a>

对于 Lambda 代理集成或 HTTP 代理集成，您的后端负责返回 `Access-Control-Allow-Origin`、`Access-Control-Allow-Methods` 和 `Access-Control-Allow-Headers` 标头，因为代理集成不返回集成响应。

以下 Lambda 函数示例返回所需的 CORS 标头：

------
#### [ Node.js ]

```
export const handler = async (event) => {
    const response = {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Headers" : "Content-Type",
            "Access-Control-Allow-Origin": "https://www.example.com",
            "Access-Control-Allow-Methods": "OPTIONS,POST,GET"
        },
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};
```

------
#### [ Python 3 ]

```
import json

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'headers': {
            'Access-Control-Allow-Headers': 'Content-Type',
            'Access-Control-Allow-Origin': 'https://www.example.com',
            'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
        },
        'body': json.dumps('Hello from Lambda!')
    }
```

------

**Topics**
+ [

## 确定是否启用 CORS 支持
](#apigateway-cors-request-types)
+ [

## 为简单请求启用 CORS
](#apigateway-cors-simple-request)
+ [

## 为非简单请求启用 CORS
](#apigateway-enable-cors-non-simple)
+ [

## 为代理集成启用 CORS 支持
](#apigateway-enable-cors-proxy)
+ [

# 使用 API Gateway 控制台对资源启用 CORS
](how-to-cors-console.md)
+ [

# 使用 API Gateway 导入 API 在资源上启用 CORS
](enable-cors-for-resource-using-swagger-importer-tool.md)
+ [

# 在 CORS 中测试 API Gateway API
](apigateway-test-cors.md)

# 使用 API Gateway 控制台对资源启用 CORS
<a name="how-to-cors-console"></a>

您可以使用 API Gateway 控制台为已创建的 REST API 资源上的一个或所有方法启用 CORS 支持。启用 COR 支持后，将集成传递行为设置为 `NEVER`。在这种情况下，将拒绝未映射内容类型的方法请求，并返回“HTTP 415 不支持的媒体类型”响应。有关更多信息，请参阅 [API Gateway 中适用于 REST API 且无映射模板的有效载荷的方法请求行为](integration-passthrough-behaviors.md)。

**重要**  
资源可以包含子资源。为某个资源及其方法启用 CORS 支持不会以递归方式为子资源及其方法启用它。

**在 REST API 资源上启用 CORS 支持**

1. 通过以下网址登录到 Amazon API Gateway 控制台：[https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)。

1. 选择一个 API。

1. 在**资源**下选择一个资源。

1. 在**资源详细信息**部分，选择**启用 CORS**。

      
![\[在“资源”窗格中，选择“启用 CORS”。\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/amazon-api-gateway-new-console-enable-cors.png)

1.  在**启用 CORS** 框中，执行以下操作：

   1. （可选）如果您创建了自定义网关响应并希望为响应启用 CORS 支持，请选择一种网关响应。

   1. 选择各方法以启用 CORS 支持。`OPTION` 方法必须启用 CORS。

      如果您为某个 `ANY` 方法启用 CORS 支持，则会为所有方法启用 CORS。

   1.  在 **Access-Control-Allow-Headers** 输入字段中，输入静态字符串，该字符串是客户端必须在实际资源请求中提交的标头列表，以逗号分隔。使用控制台提供的 `'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'` 标头列表，或指定您自己的标头。

   1. 将控制台提供的值 `'*'` 用作 **Access-Control-Allow-Origin** 标头值，以支持来自所有源的访问请求，或指定可以访问该资源的源。

   1. 选择**保存**。  
![\[选择允许的标头\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/amazon-api-gateway-new-console-enable-cors-resources.png)
**重要**  
 如果在代理集成中将以上说明应用于 `ANY` 方法，那么将不会设置任何适用的 CORS 标头。相反，您的后端必须返回适用的 CORS 标头，例如 `Access-Control-Allow-Origin`。

在 `GET` 方法上启用 CORS 后，如果资源中没有 `OPTIONS` 方法，则该方法将添加到资源中。`OPTIONS` 方法的 `200` 响应会自动配置为返回三个 `Access-Control-Allow-*` 标头，以完成预检握手。此外，默认情况下，实际 (`GET`) 方法还会配置为在 200 响应内返回 `Access-Control-Allow-Origin` 标头。对于其他类型的响应，如果您不希望返回 `Cross-origin access` 错误，您将需要手动对其进行配置，以返回带有“\$1”或特定源的 `Access-Control-Allow-Origin'` 标头。

在您的资源上启用 CORS 支持后，您必须部署或重新部署 API 以使新设置生效。有关更多信息，请参阅 [创建 部署。](set-up-deployments.md#create-deployment)。

**注意**  
如果按照此过程操作后无法在资源上启用 CORS 支持，我们建议您将您的 CORS 配置与示例 API `/pets` 资源进行比较。要了解如何创建示例 API，请参阅[教程：通过导入示例创建 REST API](api-gateway-create-api-from-example.md)。

# 使用 API Gateway 导入 API 在资源上启用 CORS
<a name="enable-cors-for-resource-using-swagger-importer-tool"></a>

如果您使用 [API Gateway 导入 API](api-gateway-import-api.md)，则可以使用 OpenAPI 文件设置 CORS 支持。您必须先在您的资源中定义可返回所需标头的 `OPTIONS` 方法。

**注意**  
Web 浏览器预计接受 CORS 请求的每个 API 方法中会设置 Access-Control-Allow 标头和 Access-Control-Allow-Origin 标头。此外，某些浏览器首先向同一资源中的 `OPTIONS` 方法发出 HTTP 请求，然后预计收到相同的标头。

## `Options` 方法示例
<a name="enable-cors-for-resource-using-swagger-importer-tool-options"></a>

以下示例创建了一个 `OPTIONS` 方法以进行模拟集成。

------
#### [ OpenAPI 3.0 ]

```
/users:
  options:
    summary: CORS support
    description: |
      Enable CORS by returning correct headers
    tags:
    - CORS
    responses:
      200:
        description: Default response for CORS method
        headers:
          Access-Control-Allow-Origin:
            schema:
              type: "string"
          Access-Control-Allow-Methods:
            schema:
              type: "string"
          Access-Control-Allow-Headers:
            schema:
              type: "string"
        content: {}
    x-amazon-apigateway-integration:
      type: mock
      requestTemplates:
        application/json: "{\"statusCode\": 200}"
      passthroughBehavior: "never"
      responses:
        default:
          statusCode: "200"
          responseParameters:
            method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
            method.response.header.Access-Control-Allow-Methods: "'*'"
            method.response.header.Access-Control-Allow-Origin: "'*'"
```

------
#### [ OpenAPI 2.0 ]

```
/users: 
   options:
      summary: CORS support
      description: |
        Enable CORS by returning correct headers
      consumes:
        - "application/json"
      produces:
        - "application/json"
      tags:
        - CORS
      x-amazon-apigateway-integration:
        type: mock
        requestTemplates: "{\"statusCode\": 200}"
        passthroughBehavior: "never"
        responses:
          "default":
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Headers : "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
              method.response.header.Access-Control-Allow-Methods : "'*'"
              method.response.header.Access-Control-Allow-Origin : "'*'"
      responses:
        200:
          description: Default response for CORS method
          headers:
            Access-Control-Allow-Headers:
              type: "string"
            Access-Control-Allow-Methods:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
```

------

在您为资源配置 `OPTIONS` 方法后，可以将所需的标头添加到同一资源中需要接受 CORS 请求的其他方法。

1. 将 **Access-Control-Allow-Origin** 和**标头**声明为响应类型。

------
#### [ OpenAPI 3.0 ]

   ```
       responses:
         200:
           description: Default response for CORS method
           headers:
             Access-Control-Allow-Origin:
               schema:
                 type: "string"
             Access-Control-Allow-Methods:
               schema:
                 type: "string"
             Access-Control-Allow-Headers:
               schema:
                 type: "string"
           content: {}
   ```

------
#### [ OpenAPI 2.0 ]

   ```
       responses:
           200:
             description: Default response for CORS method
             headers:
               Access-Control-Allow-Headers:
                 type: "string"
               Access-Control-Allow-Methods:
                 type: "string"
               Access-Control-Allow-Origin:
                 type: "string"
   ```

------

1. 在 `x-amazon-apigateway-integration` 标签中，为这些标头设置到静态值的映射：

------
#### [ OpenAPI 3.0 ]

   ```
       responses:
           default:
             statusCode: "200"
             responseParameters:
               method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
               method.response.header.Access-Control-Allow-Methods: "'*'"
               method.response.header.Access-Control-Allow-Origin: "'*'"
             responseTemplates:
               application/json: |
                 {}
   ```

------
#### [ OpenAPI 2.0 ]

   ```
       responses:
             "default":
               statusCode: "200"
               responseParameters:
                 method.response.header.Access-Control-Allow-Headers : "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
                 method.response.header.Access-Control-Allow-Methods : "'*'"
                 method.response.header.Access-Control-Allow-Origin : "'*'"
   ```

------

## API 示例
<a name="enable-cors-for-resource-using-swagger-importer-tool-complete-example"></a>

以下示例创建一个完整的 API，其中包含一个 `OPTIONS` 方法和一个集成了 `HTTP` 的 `GET` 方法。

------
#### [ OpenAPI 3.0 ]

```
openapi: "3.0.1"
info:
  title: "cors-api"
  description: "cors-api"
  version: "2024-01-16T18:36:01Z"
servers:
- url: "/{basePath}"
  variables:
    basePath:
      default: "/test"
paths:
  /:
    get:
      operationId: "GetPet"
      responses:
        "200":
          description: "200 response"
          headers:
            Access-Control-Allow-Origin:
              schema:
                type: "string"
          content: {}
      x-amazon-apigateway-integration:
        httpMethod: "GET"
        uri: "http://petstore.execute-api.us-east-1.amazonaws.com/petstore/pets"
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Origin: "'*'"
        passthroughBehavior: "never"
        type: "http"
    options:
      responses:
        "200":
          description: "200 response"
          headers:
            Access-Control-Allow-Origin:
              schema:
                type: "string"
            Access-Control-Allow-Methods:
              schema:
                type: "string"
            Access-Control-Allow-Headers:
              schema:
                type: "string"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Empty"
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Methods: "'GET,OPTIONS'"
              method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
              method.response.header.Access-Control-Allow-Origin: "'*'"
        requestTemplates:
          application/json: "{\"statusCode\": 200}"
        passthroughBehavior: "never"
        type: "mock"
components:
  schemas:
    Empty:
      type: "object"
```

------
#### [  OpenAPI 2.0  ]

```
swagger: "2.0"
info:
  description: "cors-api"
  version: "2024-01-16T18:36:01Z"
  title: "cors-api"
basePath: "/test"
schemes:
- "https"
paths:
  /:
    get:
      operationId: "GetPet"
      produces:
      - "application/json"
      responses:
        "200":
          description: "200 response"
          headers:
            Access-Control-Allow-Origin:
              type: "string"
      x-amazon-apigateway-integration:
        httpMethod: "GET"
        uri: "http://petstore.execute-api.us-east-1.amazonaws.com/petstore/pets"
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Origin: "'*'"
        passthroughBehavior: "never"
        type: "http"
    options:
      consumes:
      - "application/json"
      produces:
      - "application/json"
      responses:
        "200":
          description: "200 response"
          schema:
            $ref: "#/definitions/Empty"
          headers:
            Access-Control-Allow-Origin:
              type: "string"
            Access-Control-Allow-Methods:
              type: "string"
            Access-Control-Allow-Headers:
              type: "string"
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Methods: "'GET,OPTIONS'"
              method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
              method.response.header.Access-Control-Allow-Origin: "'*'"
        requestTemplates:
          application/json: "{\"statusCode\": 200}"
        passthroughBehavior: "never"
        type: "mock"
definitions:
  Empty:
    type: "object"
```

------

# 在 CORS 中测试 API Gateway API
<a name="apigateway-test-cors"></a>

您可以通过调用 API 并检查响应中的 CORS 标头来测试 API 的 CORS 配置。以下 `curl` 命令将 OPTIONS 请求发送到已部署的 API。

```
curl -v -X OPTIONS https://{restapi_id}.execute-api.{region}.amazonaws.com/{stage_name}
```

```
< HTTP/1.1 200 OK
< Date: Tue, 19 May 2020 00:55:22 GMT
< Content-Type: application/json
< Content-Length: 0
< Connection: keep-alive
< x-amzn-RequestId: a1b2c3d4-5678-90ab-cdef-abc123
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Headers: Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token
< x-amz-apigw-id: Abcd=
< Access-Control-Allow-Methods: DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT
```

响应中的 `Access-Control-Allow-Origin`、`Access-Control-Allow-Headers` 和 `Access-Control-Allow-Methods` 标头显示此 API 支持 CORS。有关更多信息，请参阅 [针对 API Gateway 中的 REST API 的 CORS](how-to-cors.md)。