CloudFormation API Gateway CORS 问题访问 XMLHttpRequest 被阻止
Posted
技术标签:
【中文标题】CloudFormation API Gateway CORS 问题访问 XMLHttpRequest 被阻止【英文标题】:CloudFormation API Gateway CORS issue access to XMLHttpRequest blocked 【发布时间】: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 Request
、Integration Request
、Integration Response
和Method 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-INFO
和Enable Detailed CloudWatch Metrics
和CloudWatch log role ARN*:arn:aws:iam::<ID>: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”标头时发生这种情况,您是否已经检查过? 也许这对你有帮助:***.com/questions/40292888/… 感谢@DeependraDangal,如果您查看我的模板,我会使用正确答案中的代码。 (不要担心这里的奇怪的downvote。评论它没有任何价值,因为匿名的downvoter 早就消失了。如果必须,请将您的回复放在 cmets 中,但请不要在帖子中添加投票评论 - 大多数读者不感兴趣)。 谢谢@halfer,我会记住的。 【参考方案1】:我已经解决了这个问题。主要有两点:
-
Lambda 的
IntegrationHttpMethod
必须是 POST。我找到了答案here。
模板没有允许 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
,但由于授权方的问题,我无法使swagger
或openAPI
代码在AWS::ApiGateway::RestApi
的Body
属性内工作。我会更新我的问题。
我已按照您的建议进行操作,但无法找到问题所在。我已经更新了我上面的问题。以上是关于CloudFormation API Gateway CORS 问题访问 XMLHttpRequest 被阻止的主要内容,如果未能解决你的问题,请参考以下文章
AWS Cloudformation 将 API 密钥链接到 API 网关
尝试通过 Cloudformation 创建 AWS API 网关时出错
使用 CloudFormation 的 API Gateway 自定义域
AWS:使用 cloudformation 模板将 WAF 附加到 api 网关