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

dww*_*www 101 javascript cors reactjs fetch-api create-react-app

我可以http://catfacts-api.appspot.com/api/facts?number=99通过Postman 点击这个终点并返回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;
  });
Run Code Online (Sandbox Code Playgroud)

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

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

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

sid*_*ker 163

添加mode: 'no-cors'不会神奇地使事情有效.浏览器默认阻止前端代码访问资源跨源.如果站点发送Access-Control-Allow-Origin其响应,则浏览器将放松该阻止并允许您的代码访问响应.

但是,如果某个站点没有Access-Control-Allow-Origin在其响应中发送标头,那么您的前端JavaScript代码就无法直接访问该站点的响应.特别是,指定mode: 'no-cors'不会解决这个问题(事实上它只会让事情变得更糟).

然而,有一件事是工作,如果你通过发送请求一个CORS代理,像这样:

var proxyUrl = 'https://cors-anywhere.herokuapp.com/',
    targetUrl = 'http://catfacts-api.appspot.com/api/facts?number=99'
fetch(proxyUrl + targetUrl)
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    document.querySelector("pre").innerHTML = JSON.stringify(data, null, 2);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });
Run Code Online (Sandbox Code Playgroud)
<pre></pre>
Run Code Online (Sandbox Code Playgroud)

注意:如果你去尝试使用https://cors-anywhere.herokuapp.com,你发现它已经失效,你也可以轻松地将你自己的代理部署到Heroku,只需2-3分钟,有5个命令:

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
Run Code Online (Sandbox Code Playgroud)

运行这些命令后,您最终将拥有自己运行的CORS Anywhere服务器,例如https://cryptic-headland-94862.herokuapp.com/.因此,不要在您的请求URL前加上https://cors-anywhere.herokuapp.com前缀,而是使用您自己实例的URL作为前缀; 例如,https://cryptic-headland-94862.herokuapp.com/https://example.com.


我可以http://catfacts-api.appspot.com/api/facts?number=99通过Postman 点击这个终点并返回Access-Control-Allow-Origin

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

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

您的浏览器可以很好地获得响应,您可以在Postman甚至浏览器devtools中看到它 - 但这并不意味着浏览器会将其暴露给您的代码.他们不会,因为它没有Access-Control-Allow-Origin响应标题.因此,您必须使用代理来获取它.

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


所以,我想在一个对象来传递,我取这将禁用CORS

你不想那样做.需要明确的是,当你说你想"禁用CORS"看来你实际上意味着要禁用的同源策略.CORS本身实际上是一种方式做到这一点- CORS是松开同源策略,没有办法限制它的方式.

但无论如何,你可以 - 只在你的本地环境中 - 做一些事情,例如给你的浏览器运行时标志禁用安全性并运行不安全,或者你可以在本地安装浏览器扩展来绕过同源策略,但所有这一切都可以是在本地改变你的情况.

无论你在本地改变什么,任何试图使用你的应用程序的人仍然会遇到同源策略,并且你无法为你的应用程序的其他用户禁用它.

你很可能永远不想mode: 'no-cors'在实践中使用,除非在一些有限的情况下,即使那时你只知道你正在做什么以及效果是什么.那是因为mode: 'no-cors'实际上对浏览器说的是"阻止我的前端JavaScript代码在所有情况下查看响应主体和标题的内容." 在大多数情况下,这显然不是你想要的.


至于情况下,您考虑使用<script>,请在答案适用于不透明的回应什么限制?细节.它的要点是案例是:

  • 在你使用JavaScript来使从另一个来源的内容资源时有限的情况下<link rel=stylesheet>,<img>,<video>,<audio>,<object>,<embed>,<iframe>,或href元素(它的作品,因为资源的嵌入跨域允许那些) -但由于某种原因只是通过让文档的标记使用资源URL作为元素的属性src{ mode: 'opaque'}属性,您不希望或不能这样做.

  • 当你想要用资源做的唯一事情就是缓存它.正如答案所暗示的那样,对不透明的回应有哪些限制?实际上,适用的场景是在使用Service Workers时,在这种情况下,相关的API是Cache Storage API.

但即使在这些有限的情况下,也有一些重要的问题需要注意; 看到答案在不透明的反应有哪些限制?细节.


我也试图传入这个对象 mode: 'opaque'

没有opaque请求模式 - no-cors条件只是响应的属性,并且浏览器在响应中设置了不透明条件(如果它们来自与mode: 'no-cors'模式一起发送的请求).

但顺便提一句,不透明这个词是关于你最终反应的性质的一个非常明确的信号:"不透明"意味着你看不到它.

  • 这是来自 Chrome 的一条非常愚蠢的错误消息:Access to fetch at 'http://quake.okayfun.com/maps/baseq3/index.json' from origin 'http://localhost:8080' 已被 CORS 策略阻止:请求的资源上不存在“Access-Control-Allow-Origin”标头。如果不透明响应满足您的需求,请将请求模式设置为“no-cors”以在禁用 CORS 的情况下获取资源。 (22认同)
  • 喜欢'cors-anywhere`解决方案,用于简单的非产品用例(即获取一些公开可用的数据).这个答案证实了我的怀疑,即"无人"不常见,因为它的不透明反应并不是很有用; 即"非常有限的案件"; 任何人都可以[向我解释](/sf/ask/3679892681/)的例子-cors`有用吗? (3认同)
  • CORS 代理很棒。我很惊讶它被认为是一种“安全”措施来阻止对公共文件的访问。从黑客的角度来看,这是非常非常容易绕过的,而这正是它的作用。对于好演员来说,这确实是一个麻烦。 (2认同)

小智 26

如果您尝试在本地主机上临时解决此问题,您可以使用此 Chrome 扩展程序:

允许 CORS 访问控制允许来源


小智 16

如果您使用 Express 作为后端,您只需安装cors并导入并使用它

app.use(cors());.
Run Code Online (Sandbox Code Playgroud)

如果还没有解决,请尝试切换端口。切换端口后肯定能解决

  • 我记得我高年级的大学课程,除了我们的之外,没有其他小组可以实现这一点——奇怪的是,这是一个简单的解决方案。这是更全面的指南:https://stackabuse.com/handling-cors-with-node-js/ (2认同)

小智 9

如果您需要托管解决方案,您还可以设置反向代理,使用自托管CORS AnywhereJust CORS添加 CORS 标头。

https://justcors.com/<id>/<your-requested-resource>
http://cors-anywhere.com/<your-requested-resource>
Run Code Online (Sandbox Code Playgroud)


dot*_*NET 7

因此,如果您像我一样在 localhost 上开发一个网站,尝试从 Laravel API 获取数据并在您的 Vue 前端使用它,并且您看到了这个问题,那么我是如何解决它的:

  1. 在您的 Laravel 项目中,运行 command php artisan make:middleware Cors。这将为app/Http/Middleware/Cors.php您创建。
  2. handles函数中添加以下代码Cors.php

    return $next($request)
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在 中app/Http/kernel.php,在$routeMiddleware数组中添加以下条目:

    ‘cors’ => \App\Http\Middleware\Cors::class
    
    Run Code Online (Sandbox Code Playgroud)

    (会有像阵列中的其他项目authguest等等。另外,还要确保你在做这个app/Http/kernel.php,因为还有另外一个kernel.php太Laravel)

  4. 在要允许访问的所有路由的路由注册上添加此中间件,如下所示:

    Route::group(['middleware' => 'cors'], function () {
        Route::get('getData', 'v1\MyController@getData');
        Route::get('getData2', 'v1\MyController@getData2');
    });
    
    Run Code Online (Sandbox Code Playgroud)
  5. 在 Vue 前端,请确保在mounted()函数中而不是在data(). 还要确保在通话中使用http://https://使用 URL fetch()

全部归功于皮特·休斯顿的博客文章


vol*_*lna 6

非常简单的解决方案(配置 2 分钟)是使用local-ssl-proxynpm

用法非常简单:
1. 安装软件包: npm install -g local-ssl-proxy
2. 在运行你的local-servermask时使用local-ssl-proxy --source 9001 --target 9000

PS :替换--target 9000-- "number of your port"--source 9001--source "number of your port +1"