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

我可以通过Postman到达端点http://catfacts-api.appspot.com/api/facts?number=99,它返回JSON

此外,我正在使用创建-反应-应用程序,并希望避免设置任何服务器配置。

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

请求上没有'Access-Control-Allow-Origin'报头 资源。因此,不允许使用Origin 'http://localhost:3000' 访问。如果不透明响应满足您的需求,请设置请求的

. mode to '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..我错过了什么?

764774 次浏览

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

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

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

但是,有一件事工作:如果您通过发送请求,则CORS代理

您还可以轻松地部署自己的代理到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

运行这些命令后,您将拥有自己的CORS Anywhere服务器,例如,https://cryptic-headland-94862.herokuapp.com/

以代理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甚至在浏览器devtools中看到它,但这并不意味着浏览器将它暴露给您的代码。它们不会,因为它没有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'的情况,请参阅什么限制适用于不透明的响应?< / >中的答案以了解详细信息。它的要点是:

但即使在这些有限的情况下,也有一些重要的陷阱需要注意;参见什么限制适用于不透明的响应?< / >中的答案了解详细信息。


我还试图传入对象{ mode: 'opaque'}

没有'opaque'请求模式——opaque只是响应的一个属性,浏览器在以no-cors模式发送的请求的响应上设置了这个不透明的属性。

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

我的解决方案是在服务器端进行

我使用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);
}
}

您可以根据自己的用例对其进行调整。主要问题是client.DownloadData()工作时没有任何CORS错误。通常CORS问题只发生在网站之间,因此从服务器发出“跨站点”请求是可以的。

然后,React获取调用就像这样简单:

//React component


fetch(`api/ItemImage/GetItemImageFromURL?url=${imageURL}`, {
method: 'GET',
})
.then(resp => resp.json() as Promise<ItemImage>)
.then(imgResponse => {


// Do more stuff....
)}

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

用法很直白: < br > 1。安装包: npm install -g local-ssl-proxy < br > 2. 在运行你的local-server掩码时,使用local-ssl-proxy --source 9001 --target 9000

--target 9000替换为-- "number of your port",将--source 9001替换为--source "number of your port +1"

简单的解决方法:将以下内容添加到您正在请求数据的php文件的顶部。

header("Access-Control-Allow-Origin: *");

注意:这种方法不安全,不建议在生产环境中使用!

所以如果你像我一样,在localhost上开发一个网站,你试图从Laravel API获取数据,并在你的Vue前端使用它,你看到了这个问题,这是我如何解决它:

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

    return $next($request)
    ->header('Access-Control-Allow-Origin', '*')
    ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    
  3. In app/Http/kernel.php, add the following entry in $routeMiddleware array:

    ‘cors’ => \App\Http\Middleware\Cors::class
    

    (数组中会有其他条目,如authguest等。还要确保你在app/Http/kernel.php中这样做,因为在Laravel中也有另一个kernel.php)

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

    Route::group(['middleware' => 'cors'], function () {
    Route::get('getData', 'v1\MyController@getData');
    Route::get('getData2', 'v1\MyController@getData2');
    });
    
  5. In Vue front-end, make sure you call this API in mounted() function and not in data(). Also make sure you use http:// or https:// with the URL in your fetch() call.

Full credits to Pete Houston's blog article.

如果你使用Express作为后端,你只需要安装cors并导入并在app.use(cors())中使用它; 如果无法解决,则尝试切换端口。 在交换端口

后肯定会解决

如果上述所有解决方案都不起作用,可能是因为文件权限,因为有时即使您使用Heroku或其他方式修复了非cors问题,它也会抛出403禁止错误。设置目录/文件权限如下:

权限和所有权错误 403禁止错误也可能由您的web内容文件和文件夹的所有权或权限不正确引起 < p >权限 正确权限的经验法则:

文件夹:755

静态内容:644

动态内容:700

如果您试图在您的本地主机上临时解决这个问题,您可以使用这个chrome扩展:允许CORS访问控制-允许起源 https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf < / p >

如果你想要一个托管的解决方案,你也可以设置一个反向代理,使用自托管的歌珥在任何地方只是歌珥添加CORS头。

https://justcors.com/<id>/<your-requested-resource>
http://cors-anywhere.com/<your-requested-resource>

代码的邮递员

enter image description here

Javascript

function fnlogin(){
   

var url = ("http://localhost:3000/users/login");
var method =('POST');
var data = JSON.stringify({
"email": "juan.perez@gmail.com",
"password": "12345"
});


  

var xhr = new XMLHttpRequest();
xhr.withCredentials = false; // SOLUTION False not True
  

xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
  

xhr.open(method, url ,true);
xhr.setRequestHeader("content-type", "application/json");
xhr.setRequestHeader("cache-control", "no-cache");
//xhr.send(data,{mode: 'no-cors'});
xhr.send(data);
}

我有一个类似的问题,我的浏览器调试器说我的响应。Body为null,但fiddler和开发人员工具显示它已填充,结果基本上与此相同的场景。我正在使用一个本地Angular应用程序访问运行在IISExpress上的Web Api服务。我通过遵循在这里列出的步骤来修复它,以找到正确的应用程序主机。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>