AWS SAM:请求的资源响应中不存在“Access-Control-Allow-Origin”标头

cur*_*cat 6 cors aws-cloudformation aws-lambda aws-api-gateway aws-sam-cli

我正在努力让静态网站使用 CORS 调用 API 网关。我已经使用 SAM 本地运行了下面的代码,但是我在尝试从我的静态网站(本地托管)使用 jQuery 调用我的 API 时遇到以下 CORS 错误:

Failed to load http://localhost:3000/notify: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4000' is therefore not allowed access.
Run Code Online (Sandbox Code Playgroud)

我的template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Globals:
  Api:
    # enable CORS; to make more specific, change the origin wildcard
    # to a particular domain name, e.g. "'www.example.com'"
    Cors: "'*'"

Parameters:
  RecaptchaSecret:
    Type: String

Resources:
  NotifierFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: notifier/build
      Handler: app.lambda_handler
      Runtime: python3.6
      Environment: 
        Variables:
          PARAM1: VALUE
      Events:
        Notify:
          Type: Api 
          Properties:
            Path: /notify
            Method: post

Outputs:
    NotifierApi:
      Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/notify/"
    NotifierFunction:
      Value: !GetAtt NotifierFunction.Arn
    NotifierFunctionIamRole:
      Value: !GetAtt NotifierFunctionRole.Arn
Run Code Online (Sandbox Code Playgroud)

我对GlobalsSAM中的部分的理解是它应该将该Api字段应用于我的(推断的)API 网关。

我在网上看到了一些带有 API 网关的 CORS 示例,其中其他人使用了标准的 API 网关模板,还有一些人除了 swagger 文件之外还使用了 SAM,但我一直无法看到有人成功的示例CORS 在没有 swagger 文件的情况下使用 SAM 工作(请参阅下面的参考资料)。我觉得我一定错过了一些明显的东西!

我正在使用来自 jQuery 的常规 POST 请求,如果有帮助,我可以发布我的前端代码或“已编译”的 CloudForamtion。

非常感谢任何帮助!

干杯:)

我看过的参考资料:

这是我的函数代码:

import json
import boto3
import requests

def lambda_handler(event, context):
    print "REACHED"
    print event
    ip = requests.get('http://checkip.amazonaws.com/')

    return {
        "statusCode": 200,
        "headers": {"Access-Control-Allow-Origin": "*"},
        "body": json.dumps({
            'message': 'hello world',
            'location': ip.text.replace('\n', ''),
        })
    }
Run Code Online (Sandbox Code Playgroud)

小智 1

如果您仍然对如何实现这一点感兴趣,可以直接通过 cloudformation 模板完成,如下所示,最好在发布子资源之前定义一个根模拟资源。

  MockMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: NONE
      RestApiId: STRING
      ResourceId: STRING
      HttpMethod: OPTIONS
      Integration:
        Type: MOCK
        IntegrationResponses:
          - StatusCode: 200 
            ResponseParameters:
              method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
              method.response.header.Access-Control-Allow-Methods: "'POST,OPTIONS'"
              method.response.header.Access-Control-Allow-Origin:* #Note * allows all origins
            SelectionPattern: 2\d{2}
            ResponseTemplates: 
              application/json: Empty
        PassthroughBehavior: WHEN_NO_MATCH
        RequestTemplates:
          application/json: '{"statusCode": 200}'
      MethodResponses:
        - ResponseModels:
            application/json: Empty
          ResponseParameters:
            method.response.header.Access-Control-Allow-Headers: true
            method.response.header.Access-Control-Allow-Methods: true
            method.response.header.Access-Control-Allow-Origin: true
          StatusCode: 200
Run Code Online (Sandbox Code Playgroud)

请注意,OPTIONS 是在 POST 方法之前处理预检 CORS 请求的内容。此外,如果您按照下面的方式使用 AWS_PROXY,则需要在 lambda 函数中处理标头 CORS 响应。

  POSTmethod: 
    Type: AWS::ApiGateway::Method 
    Properties:  
      HttpMethod: POST 
      RestApiId: STRING
      ResourceId: STRING
      Integration: 
        Type: AWS_PROXY 
        ConnectionType: INTERNET 
        IntegrationHttpMethod: POST 
        Credentials: STRING
        Uri: STRING
        PassthroughBehavior: WHEN_NO_TEMPLATES
        TimeoutInMillis: 10000 #Timeout in 10seconds  
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
          ResponseParameters:
              method.response.header.Access-Control-Allow-Headers: true
              method.response.header.Access-Control-Allow-Origin: true
        - StatusCode: 400
          ResponseModels:
            application/json: Empty

  OPTIONSmethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: NONE
      RestApiId: STRING
      ResourceId: STRING
      HttpMethod: OPTIONS
      Integration:
        Type: MOCK
        IntegrationResponses:
          - StatusCode: 200 
            ResponseParameters:
              method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,x-api-key,X-Amz-Security-Token'"
              method.response.header.Access-Control-Allow-Methods: "'POST,OPTIONS'"
              method.response.header.Access-Control-Allow-Origin: "'*'"
            SelectionPattern: 2\d{2}
            ResponseTemplates: 
              application/json: Empty
        PassthroughBehavior: WHEN_NO_MATCH
        RequestTemplates:
          application/json: '{"statusCode": 200}'
      MethodResponses:
        - ResponseModels:
            application/json: Empty
          ResponseParameters:
            method.response.header.Access-Control-Allow-Headers: true
            method.response.header.Access-Control-Allow-Methods: true
            method.response.header.Access-Control-Allow-Origin: true
          StatusCode: 200
Run Code Online (Sandbox Code Playgroud)