调用 AWS Lambda 时,Chrome 忽略 Access-Control-Allow-Origin 标头并因预检错误导致 CORS 失败

Posted

技术标签:

【中文标题】调用 AWS Lambda 时,Chrome 忽略 Access-Control-Allow-Origin 标头并因预检错误导致 CORS 失败【英文标题】:Chrome is ignoring Access-Control-Allow-Origin header and fails CORS with preflight error when calling AWS Lambda 【发布时间】:2020-08-25 11:22:53 【问题描述】:

我正在构建一个 ReactJS 前端,它必须使用 JS 提取从 AWS Lambdas 收集一些数据。 无论我应用什么 CORS 技术,我都无法让它发挥作用。我在这里查看了其他答案,但无济于事。

我肯定会在我的回复中添加Access-Control-Allow-Origin"*" 值(使用邮递员调用端点对此进行了验证)。此外,Chrome 抱怨使用 Response to preflight request doesn't pass access control check 进行预检,但实际上 chrome 并没有触发预检请求(OPTIONS 方法),我所看到的只是我首先尝试制作的 GET,这是真的很混乱。

我错过了什么?当没有提出 OPTIONS 预检请求时,为什么 chrome 会抱怨预检?为什么在我的回复中添加Access-Control-Allow-Origin"*" 还不够?

谢谢!

【问题讨论】:

【参考方案1】:

TL;DR:发生了预检请求,只是没有在 chrome 上显示(有一种方法可以让它们显示)。此外,例如,如果您将自定义标头用于授权令牌,则需要进行一些调整。

总结

好吧,在研究了一天并检查了其他几个答案之后,我发布了这个,因为没有一个完全适合我的问题,希望它能帮助其他面临这个问题的人。 首先,我将总结错误中涉及的几个部分,然后总结如何修复它,而不像许多帖子建议的那样诉诸任何“hackish”解决方案,例如使用 chrome 扩展绕过 CORS,或使用任何 3rd 方服务。我的设置如下所示:

ReactJS 前端,尝试使用 fetch javascript 方法发出 GET 请求,在 http://localhost:3000 上运行以进行开发 AWS Lambda 后端,它使用 JSON 有效负载(用 python 编码,不重要,但无论如何)回答 GET。此 lambda 将在其响应中添加 Access-Control-Allow-Origin:"*" 标头。 上述 AWS Lambda 是 AWS 所谓的“授权程序”的背后,这是一个在 lambda 之前运行的函数,用于检查您想要使用的任何授权标头来保护对 API 的访问。这很重要,我们稍后会看到,因为由于 AWS 内部工作的一些废话,有时您不能使用标准 HTTP Authorization 标头,并且它默认使用他们在文档和示例中建议的 authenticationToken (并且并不总是更改它有效,有很多用户在他们的论坛中报告此问题)。稍后我们会对此进行记录。 两种 API 方法(实际 API 及其授权方)都使用 AWS API Gateway 在互联网上路由和发布,简而言之,这是一种将您的 lambda 与公共 URL 配对以从其他地方调用它的方法。 Google Chrome 用作浏览器(启用其开发工具来监控事物)

错误

当尝试调用 lambda 时,chrome 会阻止 GET 请求,并在控制台上显示此错误:Response to preflight request doesn't pass access control check。我的 lambda 已经用正确的 Access-Control-Allow-Origin 标题回答了,那么,怎么了?此外,无论如何都没有发出预检OPTIONS 请求,所以这很令人困惑。

一些调试

AWS Lambda 很棒,但他们的调试工具不如我想的那么流畅,所以我用本地 expressjs 服务器替换了 lambda,只实现了两种方法:GET /foo 和 OPTIONS /foo。令我惊讶的是,当我从我的 ReactJS 前端获取 /foo 时,它确实首先调用了 OPTIONS /foo(我通过将日志添加到我的端点等来确认这一点,您也可以在 lambdas 中执行此操作,但它没那么容易)。

实际发生了什么

“预检”请求是一个 OPTIONS 请求,用于验证执行以下 GET 时实际允许的内容,但 Chrome 中的“网络”选项卡没有显示任何实际发生的 OPTIONS 请求(我记得他们曾经出现在这里)。好吧,他们在某个时候对其进行了更改,现在默认情况下它们是隐藏的。如果您希望它们再次显示(作为开发人员,我愿意),您可以通过将 out-of-blink-cors 标志更改为 disabled 重新启用它,如 here 所述。

更改此标志后,现在 OPTIONS 请求确实显示在网络标签上。从那里我可以制作 OPTIONS 响应,以便之后启用所需的 GET。使用凭据和其他情况时还有其他注意事项(我发现 this article from Mozilla 对此很有帮助),但简而言之,我的 OPTIONS 响应标头如下所示:

Access-Control-Allow-Origin: "http://localhost:3000"
Access-Control-Allow-Methods: "GET, POST, OPTIONS"
Access-Control-Allow-Headers: "authorizationToken"

(最后一个,Access-Control-Allow-Headers,在处理 AWS Lambdas 授权方时发挥作用。如果您使用该自定义标头发送您的令牌,您需要在此处允许它)。

在让 CORS 在本地工作后,为了解决我的 lambda 问题,我做了两件事:

    您需要 API 网关才能回答 OPTIONS 请求。有很多方法可以实现这一点,从编写您自己的 lambda 来回答它到让 AWS 为您模拟响应它。有关 here 的更多信息。 您需要确保您的 GET lambda 添加 Access-Control-Allow-Origin 标头,指向您的 OPTIONS 响应所做的相同值(在我的情况下,http://localhost:3000)。

之后,一切都按预期进行。

最后说明

我写这个答案是因为我发现“React-CORS-AWS-Authorization”的连词实际上并没有被我发现的任何问题所涵盖。

此外,在 chrome 上使用 localhost 进行开发可能会出现许多问题,导致建议使用像 lvh.me 这样的外部服务,但事实并非如此,并且一些答案误导性地将这个 CORS 问题与那。此外,一些答案建议使用一些 chrome 扩展完全禁用 CORS 检查,这确实是一个糟糕的安全建议。

最后,我发现制作一个简单的 expressJS 服务器来调试服务器端的事情对于理解正在发生的事情非常有帮助,因为有时您根本无法访问另一端正在发生的事情,所以也许这个建议可能会有所帮助人们会缩短处理此类事情的时间。

【讨论】:

关于 Chrome 中的 out-of-blink-cors 标志,我认为在 Chrome devtools 中至少从 Chrome 83 开始,这将不再起作用,并且 Chrome 中不再有任何选项可以重新启用已删除的行为——因此,您将无法在 Chrome 开发工具中获取有关在某些情况下有效进行调试/故障排除所需的跨域请求和响应的一些信息。但是 Firefox devtools 或 Safari devtools 没有任何类似的限制,所以我想在调试时仔细检查其中一个可能会成为最佳实践 @sideshowbarker 感谢您提供的信息。您是否有机会链接指向此的任何来源? 请参阅chromium.org/Home/loading/oor-cors 的疑难解答部分 — “无法通过 DevTools 的网络选项卡观察到与 CORS 相关的详细网络事务。 ... 将 chrome://flags/#out-of-blink-cors 设置为 Disabled ... 将在 Chrome m83 中删除” 谢谢!我不明白他们为什么朝着向用户和开发者隐藏有用信息的方向发展。 显然,根据这篇文章 (httptoolkit.tech/blog/chrome-79-doesnt-show-cors-preflight),这是暂时的。我想我们将不得不拭目以待。

以上是关于调用 AWS Lambda 时,Chrome 忽略 Access-Control-Allow-Origin 标头并因预检错误导致 CORS 失败的主要内容,如果未能解决你的问题,请参考以下文章

如何通过忽略未使用的资源从 aws cli 创建 aws java lambda 函数?

使用“事件”调用类型时未调用 AWS Lambda

在 AWS Lambda 中担任角色,在 SSM 调用时拒绝访问

AWS lambda 实例在 xstate 调用承诺时关闭

使用 AWS SDK for Java 调用 AWS Lambda 函数时如何检索 context.done() 消息?

AWS lambda:调用HeadObject操作时发生错误(404):找不到