【问题标题】:Allow Access-Control-Allow-Origin header using HTML5 fetch API使用 HTML5 fetch API 允许 Access-Control-Allow-Origin 标头
【发布时间】:2016-08-21 01:38:28
【问题描述】:

我正在使用 HTML5 提取 API。

var request = new Request('https://davidwalsh.name/demo/arsenal.json');

fetch(request).then(function(response) {
    // Convert to JSON
    return response.json();
}).then(function(j) {
    // Yay, `j` is a JavaScript object
    console.log(JSON.stringify(j));
}).catch(function(error) {
    console.log('Request failed', error)
});

我可以使用普通的 json 但无法获取上述 api url 的数据。 它抛出错误:

Fetch API 无法加载 https://davidwalsh.name/demo/arsenal.json。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,Origin 'http://localhost' 不允许访问。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

【问题讨论】:

  • 第三方服务器需要设置,客户端无能为力。
  • @epascarello:我们可以在客户端做。在幕后,XHR Request 正在进行。请检查此https://davidwalsh.name/fetch

标签: html api url fetch-api


【解决方案1】:

解决本地环境问题的解决方案

我的前端代码在 http://localhost:3000 运行,我的 API(后端代码)在 http://localhost:5000 运行

正在使用 fetch API 调用 API。最初,它抛出“cors”错误。 然后在我的后端 API 代码中添加以下代码,允许来自任何地方的源和标头。

let allowCrossDomain = function(req, res, next) {
  res.header('Access-Control-Allow-Origin', "*");
  res.header('Access-Control-Allow-Headers', "*");
  next();
}
app.use(allowCrossDomain);

但是,在舞台、产品等其他环境的情况下,您必须限制来源。

严格禁止用于更高的环境。

【讨论】:

  • 这是一个糟糕的答案。这是一个巨大的安全问题。如果您正在阅读本文,请不要这样做。
  • 这仅用于本地设置。例如做一个快速的图片有点。是的,如果其他可部署环境也是如此,则存在安全风险。对于本地人,我觉得没有。“但是,在其他环境(如舞台、产品)的情况下,您应该限制您的来源”
  • @MatJones 你忘了告诉我们该怎么做
  • @DapoMichaels 将值设置为您想要允许的实际严格值。不仅仅是*
  • @MatJones 这仅适用于本地设置。“对于更高的环境严格禁止。”
【解决方案2】:

您需要在请求数据的服务器端设置 cors 标头。 例如,如果您的后端服务器使用 Ruby on rails,请在发回响应之前使用以下代码。应该为任何后端服务器设置相同的标头。

headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, PUT, DELETE, GET, OPTIONS'
headers['Access-Control-Request-Method'] = '*'
headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'

【讨论】:

    【解决方案3】:

    https://expressjs.com/en/resources/middleware/cors.html 你必须使用cors。

    安装:

    $ npm install cors
    
    const cors = require('cors');
    app.use(cors());
    

    您必须将此代码放在您的节点服务器中。

    【讨论】:

    • 怎么知道是不是OP的服务器,是用NodeJs写的?
    • 如果你已经创建了节点服务器(开发模式),可以使用该方法在js中使用fetch。
    【解决方案4】:

    这对我有用:

    npm install -g local-cors-proxy
    

    我们要请求的具有 CORS 问题的 API 端点:

    https://www.yourdomain.com/test/list
    

    启动代理:

    lcp --proxyUrl https://www.yourdomain.com
    
     Proxy Active 
    
     Proxy Url: http://www.yourdomain.com:28080
     Proxy Partial: proxy
     PORT: 8010
    

    然后在您的客户端代码中,新的 API 端点:

    http://localhost:8010/proxy/test/list
    

    最终结果将是对 https://www.yourdomain.ie/test/list 的请求,但不会出现 CORS 问题!

    【讨论】:

    • 请确保服务器并行运行就像打开新的 cmt-prompt 窗口并运行代码 lcp --proxyUrl yourdomain.com
    • 这太棒了,拯救我的一天
    • 不确定这是如何工作的,但确实如此!...:-).. 谢谢@VigKam
    【解决方案5】:

    如果你使用 nginx 试试这个

    #Control-Allow-Origin access
    
        # Authorization headers aren't passed in CORS preflight (OPTIONS) calls. Always return a 200 for options.
        add_header Access-Control-Allow-Credentials "true" always;
        add_header Access-Control-Allow-Origin "https://URL-WHERE-ORIGIN-FROM-HERE " always;
        add_header Access-Control-Allow-Methods "GET,OPTIONS" always;
        add_header Access-Control-Allow-Headers "x-csrf-token,authorization,content-type,accept,origin,x-requested-with,access-control-allow-origin" always;
    
        if ($request_method = OPTIONS ) {
            return 200;
        }
    
    

    【讨论】:

      【解决方案6】:

      我知道这是一篇较旧的帖子,但我发现解决此错误的方法是使用我的服务器的 IP 地址,而不是在我的获取请求中使用域名。 比如:

      #(original) var request = new Request('https://davidwalsh.name/demo/arsenal.json');
      #use IP instead
      var request = new Request('https://0.0.0.0/demo/arsenal.json');
      
      fetch(request).then(function(response) {
          // Convert to JSON
          return response.json();
      }).then(function(j) {
          // Yay, `j` is a JavaScript object
          console.log(JSON.stringify(j));
      }).catch(function(error) {
          console.log('Request failed', error)
      });
      

      【讨论】:

        【解决方案7】:

        就像 epascarello 所说,托管资源的服务器需要启用 CORS。您可以在客户端做的(可能是您正在考虑的)将获取模式设置为 CORS(尽管这是我相信的默认设置):

        fetch(request, {mode: 'cors'});
        

        但是,这仍然要求服务器也启用 CORS,并允许您的域请求资源。

        查看CORS documentation,这个awesome Udacity video 解释了Same Origin Policy

        您也可以在客户端使用 no-cors 模式,但这只会给您一个不透明的响应(您无法读取正文,但响应仍可以由服务工作者缓存或由某些 API 使用, 比如<img>):

        fetch(request, {mode: 'no-cors'})
        .then(function(response) {
          console.log(response); 
        }).catch(function(error) {  
          console.log('Request failed', error)  
        });
        

        【讨论】:

        • 您能否详细说明“但这仍然需要服务器也启用 CORS,并允许您的域请求资源。”?我一直没有成功地寻找执行此操作的说明。
        • @jayscript 整个过程如下所示:在客户端,使用 javascript 进行跨源请求。在 fetch API 的情况下,“cors”模式告诉浏览器可以发出这个请求。如果您改为使用“no-cors”模式,浏览器将停止请求,因为它不是您的应用程序的来源。服务器将接收请求并做出响应。 浏览器 确认响应具有适当的 CORS 标头,如果是,则允许读取响应。如果标头不存在,浏览器将抛出错误。
        • @jayscript this MDN article 详细介绍。本质上,您需要设置以下标头的服务器之一:“Access-Control-Allow-Origin:foo.example”、“Access-Control-Allow-Methods:POST、GET、OPTIONS”、“Access-Control-Allow-Headers: X-PINGOTHER, Content-Type”,分别启用源、方法和标头。通常,'*' 用于原始标头。您还可以查看此 Google 文档和相关的代码实验室以了解 Fetch API:developers.google.com/web/ilt/pwa/working-with-the-fetch-api
        • 谢谢!这有助于我理解,当 API 服务器不包含任何标头时,不可能从具有不同来源的 API 服务器获取数据。在我处理的特定情况下,我可以访问 API 服务器代码,并且能够自己添加标头,从而启用获取。
        • 这很愚蠢,NO sending cookie 的安全问题是什么,因此允许 CORS?
        猜你喜欢
        • 1970-01-01
        • 2019-06-19
        • 2015-06-17
        • 2013-09-09
        • 2012-03-08
        • 2015-03-21
        • 2017-04-03
        • 2012-06-07
        相关资源
        最近更新 更多