【问题标题】:CloudFormation API Gateway CORS issue access to XMLHttpRequest blockedCloudFormation API Gateway CORS 问题访问 XMLHttpRequest 被阻止
【发布时间】:2019-11-03 10:34:27
【问题描述】:

我正在尝试使用 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 的创建没有任何问题,我什至仔细检查控制台上的每一页与工作 API 并发现它们的 Method RequestIntegration RequestIntegration ResponseMethod Response 用于所有方法(包括 OPTIONS)。
  • 如果我删除模板创建的资源并在同一个 API 网关中手动创建它们,那么我的代码将按预期工作。我已经使用 localhost、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 的回答。我得到了这些:

  • 我将console.log(event.requestContext); 添加到我的 Lambda 函数(用 Node.js 编写)。
  • 当我测试函数时,有 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
  • 我在API Gateway 设置中选择了Enable CloudWatch Logs-INFOEnable Detailed CloudWatch MetricsCloudWatch log role ARN*:arn:aws:iam::&lt;ID&gt;:role/ApiGatewayCloudWatchLogsRole(这是AWS 创建的角色)。
  • 但是,API Gateway 没有 CloudWatch 日志。有默认登录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 获取测试。
  • 这是我在API Gateway 中测试GET 方法得到的结果:
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 Gateway 的Body 中使用 Swagger 模板,但无法解决无效授权问题。

【问题讨论】:

  • 有时会在预检 OPTIONS 请求没有“Access-Control-Allow-Origin”标头时发生这种情况,您是否已经检查过?
  • 也许这对你有帮助:stackoverflow.com/questions/40292888/…
  • 感谢@DeependraDangal,如果您查看我的模板,我会使用正确答案中的代码。
  • (不要担心这里的奇怪的downvote。评论它没有任何价值,因为匿名的downvoter 早就消失了。如果必须,请将您的回复放在 cmets 中,但请不要在帖子中添加投票评论 - 大多数读者不感兴趣)。
  • 谢谢@halfer,我会记住的。

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


【解决方案1】:

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

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

所以对于我上面发布的模板,我需要添加这些才能使其工作:

"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"
                }]
            }
        },

【讨论】:

  • 我希望我早点看到你的答案......会节省我几个小时的挖掘......
【解决方案2】:

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

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

示例 API 网关日志:

(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

相关的 Lambda 执行日志示例:

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  

其他想法:导出损坏的 API 和工作 API 的 Swagger 定义。比较一下,看看有什么不同。从控制台执行此操作,方法是转到 Stages > Prod > Export > Export as Swagger + API Gateway Extensions。它可能与 CloudFormation 模板不完全相同,但非常接近。

【讨论】:

  • 非常感谢@dannymac!让我试试你的建议,然后回复你。
  • 关于swagger 导出。我已经这样做了,还有openAPI,但由于授权方的问题,我无法使swaggeropenAPI 代码在AWS::ApiGateway::RestApiBody 属性内工作。我会更新我的问题。
  • 我已按照您的建议进行操作,但无法找到问题所在。我已经更新了我上面的问题。
猜你喜欢
  • 2022-01-01
  • 2019-12-16
  • 2019-12-18
  • 2023-01-10
  • 2020-07-25
  • 2021-10-27
  • 2020-11-23
  • 2019-04-28
  • 1970-01-01
相关资源
最近更新 更多