对 API 网关的 CORS 请求在浏览器中不工作

CORS Request to API Gateway not working in browser

好吧,我准备好看起来很傻了。我敢打赌这是一个简单的问题,我只是没有看到我做错了什么。

我最近部署了一个设置 API 网关的 SAM 应用程序。相关配置如下

# SAM Template Headers + Some Parameters; nothing relating to this.
Resources:

  # The Api Gateway necessary for the authorizers.
  ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: !Ref Stage
      Cors: "'*'"
      Auth:
        DefaultAuthorizer: MyCognitoAuthorizer
        Authorizers:
          MyCognitoAuthorizer:
            UserPoolArn: !ImportValue  UserPoolArn
  # some other functions, but one function should do it. 
  # Verified that all functions are referencing the custom ApiGateway resource.
  PutTodosFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handlers/add.putItemHandler
      Description: Adds a todo.
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref TodosTable
      Environment:
        Variables:
          TODOS_TABLE: !Ref TodosTable
          NODE_ENV: !If [isProd, 'production', 'development']
          REGION: !Ref AWS::Region
      Events:
        PutTodo:
          Type: Api
          Properties:
            RestApiId: !Ref ApiGateway
            Path: /
            Method: PUT

这就是我觉得自己快要疯了的地方。如您所见,我的 API 网关使用 AWS Cognito 进行授权,因此我使用 Insomnia 桌面应用程序测试流程。

只要我记得提供必要的令牌,所有请求都可以正常工作。在我开始尝试通过浏览器发出相同的请求之前,我认为自己是黄金。

现在我在尝试发出请求时遇到如下错误:

Access to fetch at 'https://xpquux202j.execute-api.us-west-2.amazonaws.com/alpha/' from origin 'https://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

调用它的代码经过了一些迭代,但最近的是:

const headers = new Headers();
    headers.append('Authorization', 'Bearer <JWT Token Goes Here>');

    fetch(API_URL, {
      headers,
      method: 'options', // have tried put/get as well. Neither goes through.
      mode: 'cors' // tried cors and no-cors
    })
      .then(console.log)
      .catch(console.log);

最初由于错误我认为 API 网关端配置错误,但向端点发出 OPTIONS 请求(Insomnia)给出:

并在

中进行测试

TYIA 寻求帮助;我确定这是我遗漏的一些小东西我已经厌倦了试图解决这个问题。

好吧,原来的问题已经解决了……有点。

Tl;Dr 您可以在 AWS::Serverless::Api 调用的 Auth 键中使用 AddDefaultAuthorizerToCorsPreflight 选项,例如

  ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: !Ref Stage
      Cors: "'*'"
      Auth:
        DefaultAuthorizer: MyCognitoAuthorizer
        AddDefaultAuthorizerToCorsPreflight: false
        Authorizers:
          MyCognitoAuthorizer:
            UserPoolArn: !ImportValue  UserPoolArn

然而,这会产生另一个与 CORS 相关的问题。当您使用此设置创建 API 网关时,OPTIONS 请求在其响应中没有 Access-Control-Allow-Headers header。我仍在等待 AWS Sam 团队关于 Github 问题的回复:https://github.com/aws/serverless-application-model/issues/2136#issuecomment-915708356

到目前为止,解决方法是简单地从控制台启用 CORS,然后控制台将获得必要的授权 header。显然不是很好,但也不是特别破坏游戏。

更新

经过一番挖掘,我发现进行这些更改后 API 网关可以毫无错误地进行部署。 CORS 部分需要在 ApiGateway 资源中看起来像这样。

  ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: !Ref Stage
      Cors:
        AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
        AllowMethods: "'*'"
        AllowOrigin: "'*'"
      # same Auth: definition as above.