XMLHttpRequest 成功,而 fetch 被阻止

Posted

技术标签:

【中文标题】XMLHttpRequest 成功,而 fetch 被阻止【英文标题】:XMLHttpRequest successful while fetch is blocked 【发布时间】:2019-03-10 11:33:47 【问题描述】:

我正在尝试从前端访问 API,并且我尝试了 xhr 和 fetch api 请求。

使用 fetch 时,我收到错误“对预检请求的响应未通过访问控制检查:请求的资源上不存在 'Access-Control-Allow-Origin' 标头。因此,来源 'http://127.0.0.1:5500'不允许访问。如果不透明的响应满足您的需求,请将请求的模式设置为 'no-cors' 以获取禁用 CORS 的资源。"

但是,在使用 XHR 时,我没有收到 headers not present 警告,它成功地从 api 获取 JSON。

我不太了解 CORS,但我的理解是我请求的 api 上没有标头,因此无法获取 API。但是,xhr 是如何在 API 上假定缺少标头的情况下获取 api 的? XMLHTTPRequest 中的请求如何可能而不是 fetch 请求中的请求?我将如何使用 fetch 来获取此 API?我在下面包含了我的 fetch 和 XHR 代码以供参考。

获取代码:

fetch(requestURL,  
    headers: 
        "Content-Type": "application/json",
        'Authorisation': 'Basic' + apiKeySecured,
        "Access-Control-Allow-Origin": "*", // Required for CORS support to work
        "Access-Control-Allow-Credentials": false,
        "api-key": apiKeySecured,
    
).then(function (response) 
    return response.json();
)
    .then(function (myJson) 
        console.log(JSON.stringify(myJson));
    )
    .catch(error => console.error(error));

XHR 代码:

var xhr = new XMLHttpRequest();
xhr.withCredentials = false;

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

xhr.open("GET", requestURL);
xhr.setRequestHeader(`api-key`, apiKeySecured);

xhr.send();

【问题讨论】:

你的问题是 你不知道 CORS ...看到这个"Access-Control-Allow-Origin": "*", // Required for CORS support to work ...不,这就是导致预检的原因 - 这是一个 响应 标头,不要将其放入请求中(不要在您的请求中手动添加任何 Access-Control 标头,永远 事实上,您应该添加的唯一标头是 api-key ...然后您发出与 XHR 相同的 fetch 请求 - 目前与 XHR 相比,您在 fetch 中添加了 4 个额外的标头 【参考方案1】:

您需要为fetch 设置mode 选项。

来自docs:

// Example POST method implementation:

postData(`http://example.com/answer`, answer: 42)
  .then(data => console.log(JSON.stringify(data))) // JSON-string from `response.json()` call
  .catch(error => console.error(error));

function postData(url = ``, data = ) 
  // Default options are marked with *
    return fetch(url, 
        method: "POST", // *GET, POST, PUT, DELETE, etc.
        mode: "cors", // no-cors, cors, *same-origin
        cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
        credentials: "same-origin", // include, same-origin, *omit
        headers: 
            "Content-Type": "application/json; charset=utf-8",
            // "Content-Type": "application/x-www-form-urlencoded",
        ,
        redirect: "follow", // manual, *follow, error
        referrer: "no-referrer", // no-referrer, *client
        body: JSON.stringify(data), // body data type must match "Content-Type" header
    )
    .then(response => response.json()); // parses response to JSON

【讨论】:

【参考方案2】:

是什么触发了原始代码中的预检?

你添加的每一个额外的标题

"Content-Type": "application/json",
'Authorisation': 'Basic' + apiKeySecured,
"Access-Control-Allow-Origin": "*", // Required for CORS support to work
"Access-Control-Allow-Credentials": false,

这些都没有添加到 XHR,所以不要将它添加到 fetch

你的 fetch 应该是

fetch(requestURL,  
    headers: 
        // remove all those random headers you added
        "api-key": apiKeySecured
    ,
    mode: 'cors' // add this 
).then(response => response.json())
.then(function (myJson) 
    console.log(JSON.stringify(myJson));
)
.catch(error => console.error(error));

现在它相当于你的 XHR 代码

【讨论】:

以上是关于XMLHttpRequest 成功,而 fetch 被阻止的主要内容,如果未能解决你的问题,请参考以下文章

fetch请求数据

fetch和XMLHttpRequest

FetchAPI 的使用

请求拦截 XMLHttpRequest和fetch

Fetch请求

使用fetch/XMLHttpRequest/JQ Aajax获取数据