使用cURL访问API正常,但使用Fetch API时出现问题。

26

我知道这个问题在 Stack Overflow 上已经被讨论了很多次,但所有答案基本上都是“向服务器添加某个特定的标题”。 在这种情况下,API(Shopify)可以正常工作,并且可以轻松地通过curl进行访问。

我已经尝试过使用Axios库和Fetch API进行操作。

  • 我已经尝试了Fetch选项中的每个referrer、mode和referrerPolicy的值。
  • 我确认了我的BasicAuth凭据是正确的。
  • 我已经在多个浏览器中尝试过了。
  • 我已经从localhost、localhost.com(在我的/etc/hosts中设置了该值)以及具有真实域名的服务器中尝试过了。

我无法理解为什么这在cURL中完全正常工作,但在fetch()中却没有任何响应。

以下是我的代码缩短版本:

const apiKey = 'mykey';
const apiPassword = 'mypass';
const apibase = 'https://my-shop-domain.myshopify.com/admin/';
const endpoint = 'locations.json';

var headers = new Headers({
   "Authorization": "Basic " + btoa( apiKey + ':' + apiPassword ),
});

    fetch( apibase + endpoint {
      method: 'GET',
      headers: headers,
      mode: 'no-cors',
      // cache: "no-store",
      // referrer: "client",
      // referrerPolicy: "origin",
      // credentials: 'include'
    }).then( resp => resp.json().then( resp => {

      console.log( resp );

    })).catch( err => {

      console.error(err);

    });

返回的错误信息是:

由于CORS策略,源'https://localhost:8080'无法访问'https://my-shop-domain.myshopify.com/admin/locations.json'。预检请求的响应未能通过访问控制检查:所请求的资源上没有“Access-Control-Allow-Origin”头。如果不需要提取详细信息,您可以将请求模式设置为“no-cors”,以禁用CORS获取资源。

如果Shopify不包含 Access-Control-Allow-Origin 头,为什么cURL可以正常工作?有node和Ruby库可供访问Shopify API,因此很难相信它们完全不允许javascript访问。

所以我想问的是,我该如何在javascript中访问这个API?


默认情况下,curl不发送任何额外的标头,您可以通过使用-i选项运行curl来确认。如果您在请求中随意添加Origin标头的任何值,则应该会收到相同的错误。 - axel.michel
2
使用 -i 选项运行 curl,一切正常。我添加了 Origin 标头,如下所示:curl -i -X GET -H "Authorization:Basic abcde12345" 'https://my-store.myshopify.com/admin/locations.json' -H "Origin:localhost",它仍然正常工作。 - JakeParis
8
由浏览器来检查 Access-Control-Allow-Origin 头部信息,cURL 以及其他服务器端软件(例如 NodeJS 或 Tomcat)并不会执行此类检查。 - skyboyer
这篇文章解决了我很多疑惑:https://zemnmez.medium.com/if-cors-is-just-a-header-why-dont-attackers-just-ignore-it-63e57c323cef。任何对于为什么curl可以工作但fetch不行感到困惑的人,请务必阅读它 :) - LGenzelis
CORS解决的真正问题是,如果没有它,任何域都可以从任何其他域请求任何资源,并且他们可以在您的浏览器中已经存在的cookie的情况下这样做。因此,他们可以请求gmail.com/account,如果您已登录到gmail,则他们将看到您的帐户页面。CORS会阻止这种情况发生。(但我不明白的是,为什么浏览器不只是不发送带有CORS禁止请求的cookie。为什么要完全禁用整个请求?) - BallpointBen
这个问题已经关闭,但我认为它的措辞使它与链接的问题有所不同。如果我正在寻找我的问题,我永远不会找到链接的那个问题,因为它的措辞方式不同。因此,我认为这个问题应该重新打开,并附上其他问题的链接作为补充帮助。 - JakeParis
2个回答

1

为什么会出现这个问题?解释如下:

CORS政策是在浏览器中实现的,旨在允许网站之间共享资源,同时防止网站互相攻击:

这些策略仅适用于浏览器内部。由于cURL是在无浏览器脚本上下文的情况下进行直接HTTP请求,因此它可以正常工作。这就引出了如何绕过CORS限制的解决方案...

解决方案:

三种解决 CORS 错误的方法 - 以及 Access-Control-Allow-Origin 标头的工作原理 解释了如何绕过CORS限制。它们都通过操作请求标头/源来实现:

  1. 浏览器扩展程序。(不确定在2022年是否仍然适用。只有用户安装了浏览器扩展程序才有效。)
  2. 第三方请求代理。(演示中链接的代理现在存在滥用的限制。)
  3. 建立自己的代理。

实际上,选项#3是唯一真正的解决方案。SvelteKit端点使代理请求变得非常简单。


你仍然可以使用cors-anywhere,只需要自己托管它。 - Phil

0

你必须使用 FormData 而不是 JSON。

    var data = new FormData();
    data.append('key', 'value');

    fetch('api', {
    method: 'POST',
    body: data,
    })
    .then(response => response.json())
    .then(data => {
    console.log(data);
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接