尝试使用 fetch 和 pass in 模式:no-cors

新手上路,请多包涵

我可以通过 Postman 访问此端点 http://catfacts-api.appspot.com/api/facts?number=99 并返回 JSON

此外,我正在使用 create-react-app 并希望避免设置任何服务器配置。

在我的客户端代码中,我试图使用 fetch 来做同样的事情,但我得到了错误:

请求中不存在“Access-Control-Allow-Origin”标头

资源。因此不允许使用来源“ http://localhost:3000

使用权。如果不透明的响应满足您的需求,请设置请求的

模式为“no-cors”以获取禁用 CORS 的资源。

所以我试图将一个对象传递给我的 Fetch,这将禁用 CORS,如下所示:

fetch('http://catfacts-api.appspot.com/api/facts?number=99', { mode: 'no-cors'})
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });

有趣的是,我得到的错误实际上是这个函数的语法错误。我不确定我的实际 fetch 是否损坏,因为当我删除 { mode: ‘no-cors’ } 对象并为其提供不同的 URL 时,它工作得很好。

我也尝试传入对象 { mode: 'opaque'} ,但这会从上面返回原始错误。

我相信我需要做的就是禁用 CORS .. 我错过了什么?

原文由 dwww 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.9k
1 个回答

mode: 'no-cors' 不会神奇地使事情正常进行。事实上,这让事情变得更糟,因为它的一个作用是告诉浏览器, “阻止我的前端 JavaScript 代码在任何情况下查看响应主体和标头的内容。” 当然你永远不想那样。

来自前端 JavaScript 的跨源请求会发生什么,浏览器默认会阻止前端代码跨源访问资源。如果 Access-Control-Allow-Origin 在响应中,那么浏览器会放松阻止并允许您的代码访问响应。

但是,如果站点在其响应中未发送 Access-Control-Allow-Origin ,则您的前端代码无法直接访问该站点的响应。特别是,您不能通过指定 mode: 'no-cors' 来修复它(事实上,这将 确保 您的前端代码无法访问响应内容)。

但是,有一件事可行:如果 通过 CORS 代理 发送请求

您还可以在 2-3 分钟内轻松地将自己的代理部署到 Heroku,使用 5 个命令:

 git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master

运行这些命令后,您最终会在 https://cryptic-headland-94862.herokuapp.com/ 运行自己的 CORS Anywhere 服务器。

在您的请求 URL 前加上您的代理 URL;例如:

 https://cryptic-headland-94862.herokuapp.com/https://example.com

添加代理 URL 作为前缀会导致请求通过您的代理发出,这:

  1. 将请求转发到 https://example.com
  2. 接收来自 https://example.com 的响应。
  3. Access-Control-Allow-Origin 标头添加到响应中。
  4. 将该响应和添加的标头传递回请求的前端代码。

然后浏览器允许前端代码访问响应,因为带有 Access-Control-Allow-Origin 响应头的响应是浏览器看到的。

即使请求是触发浏览器执行 CORS 预检 OPTIONS 请求的请求,这也有效,因为在这种情况下,代理还会发回 Access-Control-Allow-HeadersAccess-Control-Allow-Methods 使预检成功所需的标头。


我可以通过 Postman 到达这个端点 http://catfacts-api.appspot.com/api/facts?number=99

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS 解释了为什么即使您可以使用 Postman 访问响应,浏览器也不允许您从前端访问响应跨源在 Web 应用程序中运行的 JavaScript 代码,除非响应包含 Access-Control-Allow-Origin 响应标头。

http://catfacts-api.appspot.com/api/facts?number=99 没有 Access-Control-Allow-Origin 响应标头,因此您的前端代码无法访问响应跨源。

您的浏览器可以很好地获得响应,您可以在 Postman 甚至浏览器开发工具中看到它——但这并不意味着浏览器将它暴露给您的代码。他们不会,因为它没有 Access-Control-Allow-Origin 响应头。所以你必须改为使用代理来获取它。

代理向该站点发出请求,获取响应,添加 Access-Control-Allow-Origin 响应标头和所需的任何其他 CORS 标头,然后将其传回您的请求代码。浏览器看到的是添加了 Access-Control-Allow-Origin 标头的响应,因此浏览器允许您的前端代码实际访问响应。


所以我试图将一个对象传递给我的 Fetch,这将禁用 CORS

你不想那样做。需要明确的是,当你说你想“禁用 CORS”时,你的意思似乎实际上是你想禁用 同源策略。 CORS 本身实际上是一种实现这一点的方法——CORS 是一种放松同源策略的方法,而不是限制它的方法。

但无论如何,你确实可以——在你的本地环境中——给浏览器运行时标志来禁用安全和不安全地运行,或者你可以在本地安装浏览器扩展来绕过同源策略,但所有这些都是在本地为您改变情况。

无论您在本地更改什么,任何其他尝试使用您的应用程序的人仍然会遇到同源策略,并且您无法为您应用程序的其他用户禁用该策略。

你很可能永远不想在实践中使用 mode: 'no-cors' 除了少数有限的情况,即使那样,也只有当你确切地知道你在做什么以及效果是什么时。这是因为设置 mode: 'no-cors' 实际上对浏览器说的是, “阻止我的前端 JavaScript 代码在任何情况下查看响应主体和标头的内容。” 在大多数情况下,这显然不是您想要的。


至于您 考虑使用 mode: 'no-cors' 的情况,请参阅 What limitations apply to opaque responses? 了解详情。它的要点是:

  • In the limited case when you’re using JavaScript to put content from another origin into a <script> , <link rel=stylesheet> , <img> , <video> , <audio> , <object> , <embed> , or <iframe> element (which works because embedding of resources cross-origin is allowed for those)—but出于某种原因,您不想/不能仅仅通过让文档的标记使用资源 URL 作为元素的 hrefsrc 属性来做到这一点。

  • 当您唯一想对资源做的事情就是缓存它时。正如 What limitations apply to opaque responses? 中提到的那样,实际上适用的场景是当您使用服务工作线程时,在这种情况下,相关的 API 是 Cache Storage API

但即使在那些有限的情况下,也有一些重要的陷阱需要注意; 请参阅 什么限制适用于不透明响应? 了解详情。


我也尝试传入对象 { mode: 'opaque'}

没有 'opaque' 请求模式 — opaque 而只是 响应 的一个属性,浏览器在使用 no-cors 发送的请求的响应中设置不透明属性

但顺便说一句, 不透明 这个词是一个非常明确的信号,表明你最终得到的反应的性质:“不透明”意味着你看不到它的任何细节;它阻止你看到。

原文由 sideshowbarker 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题