

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 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 Unsupported Media Type (不支援的媒體類型) 回應。如需詳細資訊，請參閱[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'}}` 標頭。

### 使用 為非代理整合啟用 CORS AWS 管理主控台
<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)
+ [測試 API Gateway API 的 CORS](apigateway-test-cors.md)