试图在模式中使用获取和传递: no-cors

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

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

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

请求的资源上没有'Access-Control-Allow-Origin'头。 资源。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。我错过了什么?

添加mode: 'no-cors'并不会神奇地使事情顺利进行。事实上,它使事情变得更糟,因为它的一个作用是告诉浏览器,"阻止我的前端JavaScript代码在任何情况下查看响应体和头文件的内容。"当然这几乎不是你想要的。 对于来自前端JavaScript的跨源请求,浏览器默认会阻止前端代码对资源的跨源访问。如果一个网站在其响应中发送Access-Control-Allow-Origin,那么浏览器就会放松对它的封锁,允许你的代码访问响应。 但是,如果一个网站在其响应中没有发送Access-Control-Allow-Origin头,你的前端代码就没有办法直接访问该网站的响应。特别是,你不能通过指定mode: 'no-cors'来解决这个问题(事实上这将*确保你的前端代码不能访问响应内容)。 然而,有一件事会起作用,那就是如果你通过[一个 CORS 代理][1]发送你的请求,就像这样。

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;
  });
<pre></pre>

注意:如果你去尝试使用https://cors-anywhere.herokuapp.com时,发现它已经停机了,你也可以轻松地在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前加上`https://cors-anywhere.herokuapp.com`,而是用你自己的实例的URL前缀;例如,https://cryptic-headland-94862.herokuapp.com/https://example.com

我可以通过Postman击中这个端点,http://catfacts-api.appspot.com/api/facts?number=99https://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',详情请见https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790的答案。它的要点是,这些情况是。

  • 在有限的情况下,当你使用JavaScript将另一来源的资源作为<script><amp-video><amp-audio>&lt;object>&lt;embed&gt;&lt;iframe>元素(这样做是因为这些元素允许跨源嵌入资源)--但由于某些原因,你不想或不能仅仅通过让文档的标记使用资源URL作为该元素的hrefsrc属性来实现。
  • 当你想对资源做的唯一事情就是缓存它。正如在https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790的回答中所提到的,在实践中,适用于这种情况的是当你使用服务工作者时,在这种情况下,相关的API是缓存存储API但即使在这些有限的情况下,也有一些需要注意的重要问题;详情请见https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790的回答。

    我也曾尝试传入对象{ mode: 'opaque'}。 没有mode: 'opaque'请求模式--opaque只是response的一个属性,浏览器对以no-cors模式发送的请求的响应设置该不透明属性。 但顺便说一句,opaque这个词是一个非常明确的信号,说明你最终得到的响应的性质。"不透明 "意味着你不能看到它。

评论(5)

我的解决方案是直接在服务器端进行操作

我使用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)
    .then(imgResponse => {

       // Do more stuff....
    )}
评论(0)

非常简单的解决方案(2分钟配置)是使用npmlocal-ssl-proxy包。

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

P.S:--target 9000替换为-- "你的端口的数字"--source 9001替换为--source "你的端口的数字+1"

评论(2)