在本地运行 AWS SAM CLI 时启用 CORS

问题描述 投票:0回答:5

每当我尝试通过浏览器通过 POST 访问无服务器 lambda 函数时,都会收到错误

对预检请求的响应未通过访问控制检查:请求的资源上不存在 >'Access-Control-Allow-Origin' 标头。

当它是

/GET
时,它工作得很好,我读过它是因为它没有发送飞行前请求。当我将其更改为
POST
时,它就会失败。

我正在运行的命令:

sam local start-api

我的 template.yaml 是:

...

Resources:
    PropertiesFunction:
        Type: AWS::Serverless::Function
        Properties:
            CodeUri: target/service-0.0.1-SNAPSHOT.jar
            Handler: com.aws.PropertiesHandler::handleRequest
            Runtime: java8
            Events:
                PropertiesApi:
                    Type: Api
                    Properties:
                        Path: /properties
                        Method: post

...

如何在这些端点上启用 CORS?

amazon-web-services aws-lambda aws-api-gateway serverless aws-sam-cli
5个回答
13
投票

我有同样的错误,我已经通过 3 个步骤修复了它。 (Java8 中的 AWS Lambda、SAM CLI v0.37.0)

  1. 为标题添加选项:
    Map<String, String> headers = new HashMap<>();
    headers.put("Content-Type", "application/json");
    headers.put("X-Custom-Header", "application/json");
    headers.put("Access-Control-Allow-Origin", "*");
    headers.put("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, PATCH, DELETE");
    headers.put("Access-Control-Allow-Headers", "X-Requested-With,content-type");
  1. 将 Option Cors 添加到 template.yaml 中
    Globals:
      Function:
        Timeout: 20
      Api:
        Cors:
          AllowMethods: "'GET,POST,OPTIONS'"
          AllowHeaders: "'content-type'"
          AllowOrigin: "'*'"
          AllowCredentials: "'*'"
  1. 更新 template.yaml 中的属性资源函数
          Events:
            HelloWorld:
              Type: Api 
              Properties:
                # Path: /hello
                # Method: get
                Path: "/{proxy+}"
                Method: ANY

6
投票

首先,您需要在 template.yml 中添加以下部分以在 API 网关中启用 cors:

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

然后在您的 lambda 函数响应中


        MultivaluedMap<String, Object> headers = responseContext.getHeaders();

        headers.add("Access-Control-Allow-Origin", "*");
        headers.add("Access-Control-Allow-Headers", requestContext.getHeaderString("Access-Control-Request-Headers"));
        headers.add("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,HEAD,OPTIONS");

4
投票

您应该能够通过在处理函数中将以下标头显式添加到响应中来解决本地测试的问题:

    "Access-Control-Allow-Origin": "*"

如果您在本地运行,则可以使用仅添加标头的环境变量。

这是我拥有的处理函数中的一个简单的 Python 示例:

   if not all(field in values for field in required_fields):
    response = {
        'statusCode': 400,
        'body': json.dumps(
            {
                'message': 'Required data missing from request body'
            }
        )        
    }
    # explicitly add CORs headers for local testing
    response['headers'] = {"Access-Control-Allow-Origin": "*"}
    return response

这仅适用于本地测试,当您部署到 API 网关时,COR 由 API 网关上的配置处理。

这个解决方案对我有用,直到我还使用 Cognito 用户池向 API 添加了授权,我目前正在尝试解决该问题。

这是关于该问题的类似帖子: 如何为 AWS API Gateway 资源启用 CORS

这里参考了AWS官方文档。


0
投票

如果您使用 SAM,请在无服务器模板文件上尝试此操作

"Globals": {
    "Api": {
      "Cors": {
        "AllowMethods": "'POST, GET, PUT, DELETE'",
        "AllowHeaders": "'content-type'",
        "AllowOrigin": "'*'"
      }
    }
}

0
投票

聚会有点晚了,但我一直在努力解决这个问题并找到了解决方案。希望对其他人也有帮助。我不想用额外的、不安全的标头来污染我的 lambda 代码,因此考虑在 SAM 中执行此操作。

我仅将 SAM 用于本地开发,而不用于部署,因此该解决方案可能并不适合所有人,因为它需要更改模板。

解决此问题的方法是在 SAM 模板中使用

HttpApi
而不是
'Api
。我已将以下内容添加到
Globals
部分:

Globals:
  HttpApi:
    CorsConfiguration:
      AllowHeaders:
        - Content-Type
        - Authorization
        - Access-Control-Allow-Origin
      AllowMethods:
        - '*'
      AllowOrigins:
        - '*'

然后将

Function
资源更改为
HttpApi
类型:

MyFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: api/
      Handler: management.createHandler
      Runtime: nodejs20.x
      Architectures:
      - x86_64
      Events:
        HelloWorld:
          Type: HttpApi <-- Change here
          Properties:
            Path: /announcement
            Method: post

现在当

local start-api
返回 CORS 标头时所有响应。

一件奇怪的事情,我在模板中定义了许多函数,但我只需要更改其中一个函数上的

Type
即可使标题适用于所有函数。

© www.soinside.com 2019 - 2024. All rights reserved.