CloudFormation API网关CORS发出对XMLHttpRequest的访问被阻止

时间:2019-06-20 15:00:30

标签: amazon-web-services cors amazon-cloudformation aws-api-gateway

我正在尝试使用CloudFormation创建API网关,但是它存在CORS问题。

前端错误:

POST https://<>.execute-api.us-east-1.amazonaws.com/prod/<> 500
new:1 Access to XMLHttpRequest at '<>' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
  • 该API的创建没有任何问题,我什至在控制台上对每个页面进行了仔细检查,发现它们正常工作,并且Method RequestIntegration RequestIntegration ResponseMethod Response用于所有方法(包括OPTIONS)。
  • 如果我删除模板创建的资源并在同一API网关中手动创建它们,则我的代码将按预期工作。我已经对本地主机,S3存储桶中的前端代码和PostMan进行了测试,因此我可以验证前端代码,lambda函数和数据库是否正常工作。
  • 我了解人们以前曾遇到过这个问题,但是我找不到任何能够解决我问题的答案。

  • 这里是my template

  • 请注意,"method.response.header.Access-Control-Allow-Origin": false实际上使用与工作API相同的设置来创建API。

  • 我还使用了correct answer for this question中的代码。

  • 是的,我的OPTIONS请求具有“ Access-Control-Allow-Origin”标头。

更新

以下是dannymac的回答。我得到这些:

  • 我在我的Lambda函数(用Node.js编写)中添加了console.log(event.requestContext);
  • 当我测试该功能时,会有Lambda的日志。
2019-06-27T20:07:03.118Z    462b93b2-9d4b-4ed3-bc04-f966fcd034cf    Debug CORS issue. Request ID:
2019-06-27T20:07:03.118Z    462b93b2-9d4b-4ed3-bc04-f966fcd034cf    undefined
  • 似乎没有event.requestContext
  • 我在Enable CloudWatch Logs-INFO设置中选择了Enable Detailed CloudWatch MetricsCloudWatch log role ARN*:arn:aws:iam::<ID>:role/ApiGatewayCloudWatchLogsRole(由AWS创建的角色)API Gateway
  • 但是,CloudWatch没有API Gateway日志。 CloudWatch - Log Groups中有一个默认日志:/aws/apigateway/welcome
Time (UTC +00:00)
2019-06-27
19:50:55
Cloudwatch logs enabled for API Gateway
  • 看来CloudWatch日志没有从API Gateway接受测试。
  • 这是我通过在GET中测试API Gateway方法得到的结果:
Response Body
{
  "message": "Internal server error"
}
Response Headers
{}
Logs
Execution log for request 10d90173-9919-11e9-82e1-dd33dda3b9df
Thu Jun 27 20:20:54 UTC 2019 : Starting execution for request: 10d90173-9919-11e9-82e1-dd33dda3b9df
Thu Jun 27 20:20:54 UTC 2019 : HTTP Method: GET, Resource Path: /notes
Thu Jun 27 20:20:54 UTC 2019 : Method request path: {}
Thu Jun 27 20:20:54 UTC 2019 : Method request query string: {userid=<ID>}
Thu Jun 27 20:20:54 UTC 2019 : Method request headers: {}
Thu Jun 27 20:20:54 UTC 2019 : Method request body before transformations: 
Thu Jun 27 20:20:54 UTC 2019 : Endpoint request URI: https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:770402430649:function:test-api-gateway-2-LambdaFunction-1XDONAN3QIY9I/invocations
Thu Jun 27 20:20:54 UTC 2019 : Endpoint request headers: {x-amzn-lambda-integration-tag=... [TRUNCATED]
Thu Jun 27 20:20:54 UTC 2019 : Endpoint request body after transformations: {"resource":"/notes","path":"/notes","httpMethod":"GET","headers":null,"multiValueHeaders":null,"queryStringParameters":{"userid":"<USERID>"},"multiValueQueryStringParameters":{"userid":["<USERID>"]},"pathParameters":null,"stageVariables":null,"requestContext":{"path":"/notes","accountId":"<ID>"...,"identity":{"cognitoIdentityPoolId":null,"cognitoIdentityId":null,"apiKey":"test-invoke-api-key","principalOrgId":null,"cognitoAuthenticationType":null,"userArn":"<ARN>","apiKeyId":"test-invoke-api-key-id","userAgent":..."test [TRUNCATED]
Thu Jun 27 20:20:54 UTC 2019 : Sending request to https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:<ID>:function:test-api-gateway-2-LambdaFunction-<STRING>/invocations
Thu Jun 27 20:20:54 UTC 2019 : Received response. Status: 403, Integration latency: 6 ms
Thu Jun 27 20:20:54 UTC 2019 : Endpoint response headers: {Date=Thu, 27 Jun 2019 20:20:54 GMT, Content-Length=130, Connection=keep-alive, x-amzn-RequestId=<ID>}
Thu Jun 27 20:20:54 UTC 2019 : Endpoint response body before transformations: <AccessDeniedException>
  <Message>Unable to determine service/operation name to be authorized</Message>
</AccessDeniedException>

Thu Jun 27 20:20:54 UTC 2019 : Lambda invocation failed with status: 403. Lambda request id: feb22917-0dea-4f91-a274-fb6b85a69121
Thu Jun 27 20:20:54 UTC 2019 : Execution failed due to configuration error: 
Thu Jun 27 20:20:54 UTC 2019 : Method completed with status: 500
  • 我还在Swagger 2中导出了正常工作和不正常工作的API网关。唯一的区别是:
// working one:
"x-amazon-apigateway-any-method": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "noteid",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "security": [
          {
            "mobile-notes-api-authorizer": []
          }
        ]
      }
// not working one:
"x-amazon-apigateway-any-method": {
        "produces": [
          "application/json"
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "security": [
          {
            "test-api-gateway-2-authorizer": []
          }
        ]
      }
  • 他们都有:
"headers": {
              "Access-Control-Allow-Origin": {
                "type": "string"
              },
              "Access-Control-Allow-Methods": {
                "type": "string"
              },
              "Access-Control-Allow-Headers": {
                "type": "string"
              }
            }
  • 之前,我曾尝试在API网关的Body中使用Swagger模板,但无法解决无效的授权者问题。

2 个答案:

答案 0 :(得分:1)

我的最佳猜测:您的POST lambda函数的ANY在执行期间失败,并且没有将Access-Control-Allow-Origin标头设置为* (或您的域)。每当我从一个非5XX的请求中同时收到一个CORS错误和一个OPTIONS错误时,对我来说几乎总是这样。

推荐的下一步:在将调试日志记录添加到Lambda源代码并在API Gateway Rest API中打开CloudWatch Logs之后,重现错误情况。您可以通过以下方法来执行此操作:转到API网关控制台,单击Stages> Prod> Logs/Tracing,然后检查以下两项:Enable CloudWatch Logs(日志级别:{{1} })和INFO。然后,您必须“部署”更改,以使更改生效。为此,请从Rest API的Enable Detailed CloudWatch Metrics菜单中单击Actions按钮,然后选择Resources。我还建议您从Lambda函数记录Deploy API(传递给您的处理程序的事件属性),以便将Lambda请求与API网关请求extendedRequestId绑定。

API网关日志示例:

event.requestContext.extendedRequestId

相关的Lambda执行日志示例:

(b66b3876-984b-11e9-95eb-dd93c7e40ca0) Extended Request Id: b5zpBGS3IAMFvqw=
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) Verifying Usage Plan for request: b66b3876-984b-11e9-95eb-dd93c7e40ca0. API Key: API Stage: 1234567890/Prod
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) API Key authorized because method 'ANY /forms' does not require API Key. Request will not contribute to throttle or quota limits
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) Usage Plan check succeeded for API Key and API Stage 1234567890/Prod
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) Starting execution for request: b66b3876-984b-11e9-95eb-dd93c7e40ca0
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) HTTP Method: GET, Resource Path: /forms
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) Lambda execution failed with status 200 due to customer function error: select count(*) AS `count(*)` from (select `user`.* from `user` where (id IN ('some_id_123'))) as `temp` - Cannot enqueue Query after fatal error.. Lambda request id: 1ae2bb06-5347-4775-9277-caccc42f18f2
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) Method completed with status: 502
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) AWS Integration Endpoint RequestId : 1ae2bb06-5347-4775-9277-caccc42f18f2
(b66b3876-984b-11e9-95eb-dd93c7e40ca0) X-ray Tracing ID : 1-5d13cca0-3be96a1ab93a877edc70577c

其他想法:导出损坏的API和有效API的Swagger定义。比较,看看有什么不同。通过从控制台转到START RequestId: 1ae2bb06-5347-4775-9277-caccc42f18f2 Version: $LATEST 2019-06-26T19:50:56.391Z 1ae2bb06-5347-4775-9277-caccc42f18f2 { "extendedRequestId": "b5zpBGS3IAMFvqw=", ... } 2019-06-26T19:50:57.853Z 1ae2bb06-5347-4775-9277-caccc42f18f2 { "errorMessage": "select count(*) AS `count(*)` from (select `user`.* from `user` where (id IN ('some_id_123'))) as `temp` - Cannot enqueue Query after fatal error.", ... } END RequestId: 1ae2bb06-5347-4775-9277-caccc42f18f2 REPORT RequestId: 1ae2bb06-5347-4775-9277-caccc42f18f2 Duration: 1660.45 ms Billed Duration: 1700 ms Memory Size: 256 MB Max Memory Used: 57 MB > Stages> Prod> Export来执行此操作。它可能与CloudFormation模板不完全相同,但是非常接近。

答案 1 :(得分:1)

我已经解决了这个问题。主要有两件事:

  1. Lambda的IntegrationHttpMethod必须为POST。我找到了答案here
  2. 该模板没有允许API Gateway调用Lambda函数的AWS::Lambda::Permission。 使用该模板,当您使用AWS::Lambda::Permission时,它将显示API作为Lambda函数的触发器。 但是,如果您手动创建API网关并将其与Lambda函数链接,则它不会将API网关显示为触发器,但仍然可以使用。

因此,对于我上面发布的模板,我需要添加以下内容才能使其正常工作:

"LambdaPermission": {
            "Type": "AWS::Lambda::Permission",
            "Description": "Permission for API GateWay to invoke Lambda.",
            "Properties": {
                "Action": "lambda:invokeFunction",
                "FunctionName": {
                    "Fn::GetAtt": [
                        "LambdaFunction",
                        "Arn"
                    ]
                },
                "Principal": "apigateway.amazonaws.com",
                "SourceArn": {
                    "Fn::Join": [
                        "",
                        [
                            "arn:aws:execute-api:",
                            {
                                "Ref": "AWS::Region"
                            },
                            ":",
                            {
                                "Ref": "AWS::AccountId"
                            },
                            ":",
                            {
                                "Ref": "ApiGateway"
                            },
                            "/*"
                        ]
                    ]
                }
            }
        },

然后编辑ANY,使其看起来像这样

"methodNotesANY": {
            "Type": "AWS::ApiGateway::Method",
            "DependsOn": "LambdaPermission",
            "Properties": {
                "AuthorizationType": "COGNITO_USER_POOLS",
                "AuthorizerId": {
                    "Ref": "GatewayAuthorizer"
                },
                "RestApiId": {
                    "Ref": "ApiGateway"
                },
                "ResourceId": {
                    "Ref": "resourceNotes"
                },
                "HttpMethod": "ANY",
                "Integration": {
                    "Type": "AWS_PROXY",
                    "IntegrationHttpMethod": "POST",
                    "Uri": {
                        "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations"
                    },
                    "IntegrationResponses": [{
                        "StatusCode": "200"
                    }]
                },
                "MethodResponses": [{
                    "ResponseModels": {
                        "application/json": "Empty"
                    },
                    "StatusCode": "200"
                }]
            }
        },