提问人:dwww 提问时间:4/7/2017 最后编辑:sideshowbarkerdwww 更新时间:5/10/2023 访问量:1031837
尝试使用获取和传递模式:no-cors
Trying to use fetch and pass in mode: no-cors
问:
我可以通过 Postman 命中此端点,它会返回http://catfacts-api.appspot.com/api/facts?number=99
JSON
此外,我正在使用 create-react-app,并希望避免设置任何服务器配置。
在我的客户端代码中,我尝试用它来做同样的事情,但我收到错误:fetch
请求的标题上不存在“Access-Control-Allow-Origin”标头 资源。因此,不允许使用原产地“http://localhost:3000” 访问。如果不透明的响应满足您的需求,请将请求的 mode 设置为“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;
});
有趣的是,我得到的错误实际上是此函数的语法错误。我不确定我的实际情况是否损坏,因为当我删除 { mode: 'no-cors' } 对象并为其提供不同的 URL 时,它可以正常工作。fetch
我也尝试传入对象,但这会从上面返回原始错误。{ mode: 'opaque'}
我活着,我需要做的就是禁用CORS。我错过了什么?
答:
mode: 'no-cors'
不会神奇地让事情顺利进行。事实上,它使事情变得更糟,因为它的一个效果是告诉浏览器,“阻止我的前端 JavaScript 代码在任何情况下都看不到响应正文和标头的内容。当然,你永远不希望那样。
来自前端 JavaScript 的跨域请求的情况是,默认情况下,浏览器会阻止前端代码跨域访问资源。如果在响应中,则浏览器会放宽该阻止,并允许代码访问响应。Access-Control-Allow-Origin
但是,如果一个站点在其响应中发送 no,则您的前端代码无法直接访问来自该站点的响应。特别是,你不能通过指定来修复它(事实上,这将确保你的前端代码无法访问响应内容)。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
运行这些命令后,您最终将获得自己的 CORS Anywhere 服务器,例如,.https://cryptic-headland-94862.herokuapp.com/
在请求 URL 前面加上您的代理 URL;例如:
https://cryptic-headland-94862.herokuapp.com/https://example.com
将代理 URL 添加为前缀会导致通过代理发出请求,这:
- 将请求转发到 。
https://example.com
- 接收来自 的响应。
https://example.com
- 将标头添加到响应中。
Access-Control-Allow-Origin
- 将该响应(以及添加的标头)传递回请求的前端代码。
然后,浏览器允许前端代码访问响应,因为带有响应标头的响应是浏览器看到的。Access-Control-Allow-Origin
即使请求是触发浏览器执行 CORS 预检请求的请求,这也有效,因为在这种情况下,代理还会发回使预检成功所需的 and 标头。OPTIONS
Access-Control-Allow-Headers
Access-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
代理向该站点发出请求,获取响应,添加响应标头和所需的任何其他 CORS 标头,然后将其传递回请求代码。添加标头的响应是浏览器看到的,因此浏览器允许您的前端代码实际访问响应。Access-Control-Allow-Origin
Access-Control-Allow-Origin
所以我正在尝试将一个对象传递给我的 Fetch,这将禁用 CORS
你不想那样做。需要明确的是,当您说要“禁用 CORS”时,似乎实际上意味着要禁用同源策略。CORS 本身实际上是一种做到这一点的方法——CORS 是一种放松同源策略的方法,而不是限制它的方法。
但无论如何,在本地环境中,您确实可以做一些事情,例如提供浏览器运行时标志以禁用安全性和不安全地运行,或者您可以在本地安装浏览器扩展以绕过同源策略,但所做的只是在本地为您改变情况。
无论你在本地进行什么更改,任何尝试使用你的应用的人仍然会遇到同源策略,并且你无法为应用的其他用户禁用该策略。
你很可能永远不想使用模式:除了少数有限的情况下,在实践中是“no-cors”
,即使这样,也只有在你确切地知道你在做什么以及效果是什么的情况下。这是因为设置实际上对浏览器说的是,“在任何情况下都阻止我的前端 JavaScript 代码查看响应正文和标头的内容。在大多数情况下,这显然不是你想要的。mode: 'no-cors'
至于您希望考虑使用的情况,请参阅不透明响应适用哪些限制?它的要点是:mode: 'no-cors'
在有限的情况下,当您使用 JavaScript 将来自另一个源的内容放入 、 、 、 或元素中时(这之所以有效,因为这些元素允许跨源嵌入资源)——但出于某种原因,您不想/不能仅仅通过让文档的标记使用资源 URL 作为元素的 or 属性来做到这一点。
<script>
<link rel=stylesheet>
<img>
<video>
<audio>
<object>
<embed>
<iframe>
href
src
当您唯一想对资源执行的操作是缓存它时。正如哪些限制适用于不透明响应?中所述,在实践中,使用Service Worker时,在这种情况下,相关的API是缓存存储API。
但即使在这些有限的情况下,也有一些重要的问题需要注意;有关详细信息,请参阅不透明响应有哪些限制?
我也尝试传入对象
{ mode: 'opaque'}
没有请求模式 — 它只是响应的一个属性,浏览器在使用模式发送的请求的响应上设置该不透明属性。'opaque'
opaque
no-cors
但顺便说一句,不透明这个词是一个非常明确的信号,表明你最终得到的反应的性质:“不透明”意味着你看不到它的任何细节;它挡住了你的视线。
评论
mode: 'no-cors'
http://cors-anywhere.herokuapp.com
no-cors
对我来说,解决方案是只在服务器端做
我使用 C# 库来获取数据(在我的情况下是图像数据)并将其发送回客户端。在你选择的服务器端语言中可能有一些非常相似的东西。WebClient
//Server side, api controller
[Route("api/ItemImage/GetItemImageFromURL")]
public IActionResult GetItemImageFromURL([FromQuery] string url)
{
ItemImage image = new ItemImage();
using(WebClient client = new WebClient()){
image.Bytes = client.DownloadData(url);
return Ok(image);
}
}
您可以将其调整为自己的用例。要点是没有任何CORS错误。通常,CORS问题仅在网站之间发生,因此可以从服务器发出“跨站点”请求。client.DownloadData()
然后 React fetch 调用就这么简单了:
//React component
fetch(`api/ItemImage/GetItemImageFromURL?url=${imageURL}`, {
method: 'GET',
})
.then(resp => resp.json() as Promise<ItemImage>)
.then(imgResponse => {
// Do more stuff....
)}
评论
非常简单的解决方案(2 分钟配置)是使用 local-ssl-proxy 包npm
用法很简单:
1.安装软件包:
2. 在运行掩码时,使用npm install -g local-ssl-proxy
local-server
local-ssl-proxy --source 9001 --target 9000
附言:替换为 和--target 9000
-- "number of your port"
--source 9001
--source "number of your port +1"
评论
因此,如果您像我一样在 localhost 上开发一个网站,您尝试从 Laravel API 获取数据并在您的 Vue 前端使用它,并且您看到了这个问题,以下是我解决它的方法:
- 在Laravel项目中,运行命令。这将为您创建。
php artisan make:middleware Cors
app/Http/Middleware/Cors.php
在函数中添加以下代码:
handles
Cors.php
return $next($request) ->header('Access-Control-Allow-Origin', '*') ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
在 中,在数组中添加以下条目:
app/Http/kernel.php
$routeMiddleware
‘cors’ => \App\Http\Middleware\Cors::class
(数组中还会有其他条目,如 等。还要确保你这样做,因为拉拉维尔也有另一个)
auth
guest
app/Http/kernel.php
kernel.php
在路由注册时为要允许访问的所有路由添加此中间件,如下所示:
Route::group(['middleware' => 'cors'], function () { Route::get('getData', 'v1\MyController@getData'); Route::get('getData2', 'v1\MyController@getData2'); });
- 在 Vue 前端中,请确保在函数中调用此 API,而不是在 中调用。此外,请确保在通话中使用 URL 或 URL。
mounted()
data()
http://
https://
fetch()
完全归功于 Pete Houston 的博客文章。
评论
如果您使用 Express 作为后端,您只需安装并导入并在cors
app.use(cors());.
如果未解决,请尝试切换端口。 切换端口后肯定会解决
评论
Access-Control-Allow-Origin
如果上述所有解决方案都不起作用,可能是因为文件权限,因为有时即使您使用 Heroku 或其他方式修复了非 cors 问题,它也会抛出 403 禁止错误。设置目录/文件权限,如下所示:
权限和所有权错误 403 禁止访问错误也可能是由对 Web 内容文件和文件夹的所有权或权限不正确引起的。
权限 正确权限的经验法则:
文件夹:755
静态内容:644
动态内容:700
如果您尝试在本地主机上临时解决此问题,则可以使用此Chrome扩展程序:
如果需要托管解决方案,还可以设置反向代理,该代理使用自承载的 CORS Anywhere 或 Just CORS 添加 CORS 标头。
https://justcors.com/<id>/<your-requested-resource>
http://cors-anywhere.com/<your-requested-resource>
评论
Cors-anywhere
似乎是更好的选择,因为它是永久性的而不是暂时的,必须每天更新。justcors
我的浏览器调试器也遇到了类似的问题,说我的response.body为null,但fiddler和开发人员工具将其显示为已填充,结果与此基本相同。我正在使用本地 Angular 应用程序访问在 IISExpress 上运行的 Web Api 服务。我按照此处概述的步骤找到正确的applicationhost.config文件以添加Access-Control-Allow-Origin标头来修复它,如下所示:
<customHeaders>
<clear />
<add name="X-Powered-By" value="ASP.NET" />
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
就我而言,删除以前添加的内容解决了类似的问题,并且对我没有任何.headers: { 'Content-Type': 'application/json' }
mode cors/no-cors
当然,我的后端在响应中添加了适当的标头。Access-Control-Allow-Origin: *
评论
我必须为任何提出 CORS 请求的人添加一些注释。
- 确保两个网站都使用 HTTPS。如果要设置
withCredentials: true
并通过 cookie 发送,则 CORS 仅通过 HTTPS 工作。 - 在服务器端配置 CORS(例如 Nginx 配置)。
下面是 Nginx 配置的示例。
server {
# CORS block BEGIN
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Headers' 'x-requested-with, Content-Type, origin, authorization, accept, client-security-token';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,PATCH,DELETE';
add_header 'Access-Control-Allow-Credentials' 'true';
# CORS block END
}
$http_origin
只能在开发服务器上使用。将其替换为您的 生产服务器上的域。其余的,请继续搜索。
引用:
fetch(url, {mode: 'cors'})
对我有用。
基本上fetch(url, {requestParameterDataObject})
fetch JS 文档将包含有关请求参数对象中特定字段名称的更多信息。在这里,我们使用请求的 mode 字段并将其设置为 'cors'。
我的最终代码:
useEffect(() => {
// Loading while etching API data
setIsLoading(true);
fetch(url, {mode: 'cors'})
.then((response) => response.json())
.then((data) => {
setData(data);
// Turn off loading flag once data comes back
setIsLoading(false);
});
}, [url]);
评论