我可以通过 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 许可协议
mode: 'no-cors'
不会神奇地使事情正常进行。事实上,这让事情变得更糟,因为它的一个作用是告诉浏览器, “阻止我的前端 JavaScript 代码在任何情况下查看响应主体和标头的内容。” 当然你永远不想那样。来自前端 JavaScript 的跨源请求会发生什么,浏览器默认会阻止前端代码跨源访问资源。如果
Access-Control-Allow-Origin
在响应中,那么浏览器会放松阻止并允许您的代码访问响应。但是,如果站点在其响应中未发送
Access-Control-Allow-Origin
,则您的前端代码无法直接访问该站点的响应。特别是,您不能通过指定mode: 'no-cors'
来修复它(事实上,这将 确保 您的前端代码无法访问响应内容)。但是,有一件事可行:如果 您 通过 CORS 代理 发送请求。
您还可以在 2-3 分钟内轻松地将自己的代理部署到 Heroku,使用 5 个命令:
运行这些命令后,您最终会在
https://cryptic-headland-94862.herokuapp.com/
运行自己的 CORS Anywhere 服务器。在您的请求 URL 前加上您的代理 URL;例如:
添加代理 URL 作为前缀会导致请求通过您的代理发出,这:
https://example.com
。https://example.com
的响应。Access-Control-Allow-Origin
标头添加到响应中。然后浏览器允许前端代码访问响应,因为带有
Access-Control-Allow-Origin
响应头的响应是浏览器看到的。即使请求是触发浏览器执行 CORS 预检
OPTIONS
请求的请求,这也有效,因为在这种情况下,代理还会发回Access-Control-Allow-Headers
和Access-Control-Allow-Methods
使预检成功所需的标头。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
标头的响应,因此浏览器允许您的前端代码实际访问响应。你不想那样做。需要明确的是,当你说你想“禁用 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 作为元素的href
或src
属性来做到这一点。当您唯一想对资源做的事情就是缓存它时。正如 What limitations apply to opaque responses? 中提到的那样,实际上适用的场景是当您使用服务工作线程时,在这种情况下,相关的 API 是 Cache Storage API 。
但即使在那些有限的情况下,也有一些重要的陷阱需要注意; 请参阅 什么限制适用于不透明响应? 了解详情。
没有
'opaque'
请求模式 —opaque
而只是 响应 的一个属性,浏览器在使用no-cors
发送的请求的响应中设置不透明属性但顺便说一句, 不透明 这个词是一个非常明确的信号,表明你最终得到的反应的性质:“不透明”意味着你看不到它的任何细节;它阻止你看到。