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

jot*_*cas 4 ajax google-chrome cors reactjs aws-lambda

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

我肯定会在我的响应中添加Access-Control-Allow-Origin价值"*"(使用邮递员调用端点来验证这一点)。另外,Chrome 抱怨预检Response to preflight request doesn't pass access control check,但OPTIONSChrome 实际上没有触发任何预检请求(方法),我所看到的只是GET我首先尝试做的事情,这真的很令人困惑。

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

谢谢!

jot*_*cas 7

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

概括

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

  • ReactJS前端,尝试使用fetch javascript方法发出GET请求,在http://localhost:3000上运行进行开发
  • AWS Lambda 后端,使用 JSON 负载应答 GET(用 python 编码,不重要,但无论如何)。该 lambda 正在Access-Control-Allow-Origin:"*"向其响应添加标头。
  • 上面的 AWS Lambda 是 AWS 所谓的“Authorizer”的背后,它是一个在 lambda 之前运行的函数,用于检查您想要用来保护对 API 的访问的任何授权标头。这很重要,我们稍后会看到,因为由于 AWS 内部工作原理的一些废话,有时您无法使用标准 HTTP 授权标头,并且它默认使用authorizationToken,正如他们在文档和示例中建议的那样(并且并不总是更改它)有效,有很多用户在他们的论坛中报告了这一点)。我们稍后会对此进行记录。
  • 两种 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 (我通过向端点添加日志等来确认这一点,你也可以在 lambda 中执行此操作,但并不那么容易)。

到底发生了什么

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

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

Access-Control-Allow-Origin: "http://localhost:3000"
Access-Control-Allow-Methods: "GET, POST, OPTIONS"
Access-Control-Allow-Headers: "authorizationToken"
Run Code Online (Sandbox Code Playgroud)

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

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

  1. 您需要 API 网关能够应答 OPTIONS 请求。有多种方法可以实现这一目标,从编写您自己的 lambda 来回答它,到让 AWS 为您模拟响应。更多信息请参见此处
  2. 您需要确保您的 GET lambda 添加Access-Control-Allow-Origin标头,指向您的 OPTIONS 响应所做的相同值(在我的例子中,http://localhost:3000)。

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

最后的注释

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

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

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