

# 针对 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)