如何使用 AWS SAM 启用 CORS

How to enable CORS with AWS SAM

我正在尝试在我的 AWS SAM 应用程序中启用 CORS。这是我的 template.yaml:

的片段
Globals:
  Api:
    Cors:
      AllowMethods: "'*'"
      AllowHeaders: "'*'"
      AllowOrigin: "'*'"

Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: prod
      Auth:
        Authorizers:
          MyCognitoAuthorizer: ...

  getByIdFunc:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handler.handle
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /{id}
            Method: GET
            RestApiId: !Ref MyApi

根据这个 and that https://github.com/aws/serverless-application-model/issues/373,cors 配置应该可以工作,但不幸的是 API 响应中没有设置 header,如下所示。

< HTTP/2 200 
< content-type: application/json
< content-length: 770
< date: Tue, 13 Apr 2021 19:55:31 GMT
< x-amzn-requestid: ...
< x-amz-apigw-id: ...
< x-amzn-trace-id: Root=1-...-...;Sampled=0
< x-cache: Miss from cloudfront
< via: 1.1 ...cloudfront.net (CloudFront)
< x-amz-cf-pop: FRA2-C2
< x-amz-cf-id: ...==
< 
* Connection #0 to host ....execute-api.eu-central-1.amazonaws.com left intact
[{"model": ..}]

我也尝试将 cors 配置添加到 API 定义 (MyApi) 本身,就像 offical docs here 中所述,但没有成功。

我可以自己在响应中添加 header,但我宁愿将其添加到模板文件中。

使用 SAM/CLoudformation 或 AWS 控制台,您可以为 OPTIONS 方法设置 CORS headers,浏览器将在调用您的实际 API 方法(GE/POST 等)之前调用该方法.从邮递员或任何其他服务只会调用您的端点。

当我们使用 lambda proxy with API Gateway 时,我们需要在来自 lambda 的响应 object 中设置 CORS headers。

To enable CORS for the Lambda proxy integration, you must add Access-Control-Allow-Origin:domain-name to the output headers. domain-name can be * for any domain name.

return {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Headers" : "Content-Type",
            "Access-Control-Allow-Origin": "*", // Allow from anywhere 
            "Access-Control-Allow-Methods": "GET" // Allow only GET request 
        },
        body: JSON.stringify(response)
    }

使用您的脚本,CORS 在 API 网关上启用,但 SAM 始终创建从 API 网关到 Lambda 的代理集成,这意味着 API 网关无法添加任何集成response ,它将传递将从 LAMBDA 收到的响应。这就是为什么您需要在 lambda 中处理 CORS header 而不是依赖于 API 网关。下面是来自 LAMBDA 的 return 的示例代码以及响应。

return {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Headers" : "Content-Type,X-Amz-Date,Authorization,X-Api-Key,x-requested-with",
            "Access-Control-Allow-Origin": "*", // Allow from anywhere 
            "Access-Control-Allow-Methods": "OPTIONS,POST,GET,PUT,DELETE,PATCH" // Allow only GET request 
        },
        body: JSON.stringify(response)
    }

晚会迟到了,但对于来自 Google 的其他人:将此添加到 Auth 部分,这将不允许 Authorizer 处理 CORS HTTP headers

Api:
  Auth:
    AddDefaultAuthorizerToCorsPreflight: false

为我解决的是将以下内容添加到我的 template.yaml:

Globals:
    Api:
        Cors:
            AllowMethods: "'GET,POST,OPTIONS'"
            AllowHeaders: "'content-type'"
            AllowOrigin: "'*'"
            AllowCredentials: true

就像 nirvana124 和 Nitesh 所说的那样,您还需要 return 这些 headers 以及每个端点的响应:

return {
    statusCode: 200,
    headers: {
        "Access-Control-Allow-Headers" : "Content-Type",
        "Access-Control-Allow-Origin": "*", // Allow from anywhere 
        "Access-Control-Allow-Methods": "GET" // Allow only GET request 
    },
    body: JSON.stringify(response)
}

对于使用 API 网关版本 2 的任何人(HttpApi), it doesn't have support for 'AddDefaultAuthorizerToCorsPreflight', at least not specified in their documentation

相反(根据 AWS guidelines),我们需要在 lambda 函数中为 OPTIONS /{proxy+} 添加路由并关闭该路由的身份验证。

MyHttpApi:
 Type: AWS::Serverless::HttpApi
 Properties:
  Auth:
    DefaultAuthorizer: OAuth2
    Authorizers:
      OAuth2:
        JwtConfiguration:
          issuer: "..."
          audience:
            - ...
        IdentitySource: "$request.header.Authorization"
  CorsConfiguration:
    AllowOrigins:
      - "*"
    AllowMethods: 
      - GET
      - POST
      - OPTIONS
    AllowHeaders:
      - Content-Type
      - Accept
      - Access-Control-Allow-Headers
      - Access-Control-Request-Method
      - Access-Control-Request-Headers
      - Authorization
MyLambdaFunction:
 Type: AWS::Serverless::Function
 Properties:
  Handler: index.handler
  Events:
    CorsPreflightEvent:
      Type: HttpApi
      Properties:
        Path: /{proxy+}
        Method: OPTIONS
        Auth:
          Authorizer: NONE
        ApiId: !Ref MyHttpApi