简单的了解下 Fetch API 的工作原理

Posted ischengzi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单的了解下 Fetch API 的工作原理相关的知识,希望对你有一定的参考价值。

一、简介

Fetch API是一种现代的Web API,提供了一种异步获取网络资源的方法。由于其简单性、灵活性和一致性,它已经成为Web应用程序中获取数据和资源的流行选择。在本文中,我们将深入探讨Fetch API的核心特性,并了解其工作原理。

二、Fetch API的工作原理是什么?

Fetch API基于Promise API,该API提供了一种一致而优雅的方式来处理JavaScript中的异步操作。当您调用fetch()函数时,它返回一个Promise对象,如果请求成功,则该对象将解析为一个Response对象,否则将拒绝并返回错误。

在底层,Fetch API使用XMLHttpRequest对象向服务器发送HTTP请求并接收响应。XMLHttpRequest是一个低级API,早期的Web应用程序就使用了它,并且被许多其他Web API使用,包括AJAX和WebSockets。

当您调用fetch()函数时,它创建一个新的XMLHttpRequest对象并设置事件侦听器来处理来自服务器的响应。fetch()函数还接受一个可选的options对象,允许您自定义HTTP请求,包括HTTP方法、标头和正文。

以下是使用Fetch API获取网络资源的示例:

fetch(\'https://abc.com/data.json\')
 .then(response => response.json())
 .then(data => console.log(data))
 .catch(error => console.error(error));

在这个示例中,我们使用fetch()从服务器获取一个JSON文件。一旦接收到响应,我们调用Response对象上的json()方法来提取响应中的JSON数据。然后将数据记录到控制台中。如果出现错误,我们将错误记录到控制台中。

Fetch API还支持各种HTTP方法,包括GET、POST、PUT、DELETE和其他方法。您可以使用options对象指定HTTP方法,如下所示:

fetch(\'https://abc.com/data.json\', 
  method: \'POST\',
  body: JSON.stringify( foo: \'bar\' ),
  headers: 
    \'Content-Type\': \'application/json\'
  
)
.then(response => console.log(response))
.catch(error => console.error(error));

在这个示例中,我们使用fetch()发送一个带有JSON负载的POST请求到服务器。我们设置Content-Type标头为application/json,以指示负载为JSON数据。

Fetch API还支持各种其他功能,包括请求和响应标头、请求和响应模式、cookies等。

三、简化的示例

这是一个简化的JavaScript实现Fetch API的示例,它解释了Fetch API的工作原理:

function fetch(url, options) 
  // 创建一个新的Promise对象
  return new Promise((resolve, reject) => 
    // 创建一个新的XMLHttpRequest对象
    const xhr = new XMLHttpRequest();

    // 处理服务器的响应
    xhr.onload = () => 
      // 创建一个新的Response对象并解析响应数据
      const response = new Response(xhr.responseText, 
        status: xhr.status,
        statusText: xhr.statusText,
        headers: xhr.getAllResponseHeaders()
      );
      resolve(response); // 请求成功,解析为Response对象并解析Promise对象
    ;

    // 处理获取数据过程中出现的任何错误
    xhr.onerror = () => 
      reject(new TypeError(\'Network request failed\')); // 请求失败,拒绝Promise对象并返回一个TypeError错误
    ;

    // 打开到服务器的连接
    xhr.open(options.method || \'GET\', url);

    // 设置任何提供的标头
    for (const header in options.headers) 
      xhr.setRequestHeader(header, options.headers[header]);
    

    // 发送请求到服务器
    xhr.send(options.body);
  );

这个Fetch API的实现使用了XMLHttpRequest对象,它是现代Web API的基础网络API。以下是它的工作原理:

  • fetch()函数接受两个参数:要获取的资源的URL和包含有关请求的任何其他信息(如标头、要使用的HTTP方法和请求体)的options对象。

  • fetch()函数创建一个新的Promise对象并返回它。如果请求成功,Promise将解析为一个Response对象,否则将拒绝并返回一个错误。

  • fetch()函数创建一个新的XMLHttpRequest对象,该对象将用于向服务器发送实际的HTTP请求。

  • 当从服务器接收到响应时,xhr.onload()函数被调用。该函数创建一个新的Response对象,该对象填充响应数据(响应主体、标头、状态代码和状态文本)。然后将Response对象传递给resolve()函数,该函数解析fetch()返回的Promise。

  • 如果在获取资源时发生错误,则调用xhr.onerror()函数。该函数创建一个带有消息“Network request failed”的新TypeError对象,并将其传递给reject()函数,该函数拒绝fetch()返回的Promise。

  • xhr.open()函数用于打开到服务器的连接。它接受两个参数:要使用的HTTP方法(如果没有提供,则默认为“GET”)和要获取的资源的URL。

  • xhr.setRequestHeader()函数用于设置在options对象中提供的任何标头。这通过迭代options.headers对象的属性并逐个设置每个标头来完成。

  • xhr.send()函数用于向服务器发送实际的HTTP请求。如果请求有一个请求体,则它作为参数传递给send()函数。

这个Fetch API的实现是简化的,并不包括所有实际的Fetch API的功能,但是它应该能够让你了解它的底层工作原理。

四、总结

Fetch API为Web应用程序提供了一种强大而灵活的方式来获取网络资源。在底层,它使用XMLHttpRequest对象向服务器发送HTTP请求并接收响应。通过使用Promise和一致的API,Fetch API使JavaScript中的异步操作变得容易处理。通过支持HTTP方法、标头和其他功能,Fetch API已经成为现代Web应用程序中获取数据和资源的流行选择。

来源:微信公众号[前端达人]

使用 cURL 访问 API 可以正常工作,但不能使用 Fetch API

【中文标题】使用 cURL 访问 API 可以正常工作,但不能使用 Fetch API【英文标题】:Accessing API works fine with cURL but not with Fetch API 【发布时间】:2019-04-29 14:48:53 【问题描述】:

我知道这已经在 SO 上解决了很多次 很多 次,但所有答案大多都是“向服务器添加某个标头”。在这种情况下,API (Shopify) 工作得非常好,可以通过 curl 轻松访问。

我在 Axios 库和 Fetch API 上都试过了。

我已经尝试了 Fetch 选项中 referrermodereferrerPolicy 的每个值。 我已经确认我的 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);

    );

返回的错误是

从源“https://localhost:8080”获取“https://my-shop-domain.myshopify.com/admin/locations.json”的访问权限已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:没有“Access-Control-Allow-Origin”标头出现在请求的资源上。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

如果 Shopify 不包含 Access-Control-Allow-Origin 标头,为什么请求可以正常使用 cURL?有节点库和 Ruby 库可以访问 Shopify API,因此很难相信它们根本不允许从 javascript 访问。

所以我想我的问题是如何使用 javascript 访问此 API?

【问题讨论】:

默认情况下 curl 不会发送任何额外的标头,您可以通过运行带有 -i 选项的 curl 来确认。如果您在 Origin 标头中随请求发送任意值,您应该会收到相同的错误。 使用-i 选项运行curl,效果很好。我这样添加了 Origin 标头:curl -i -X GET -H "Authorization:Basic abcde12345" 'https://my-store.myshopify.com/admin/locations.json' -H "Origin:localhost",它仍然可以正常工作。 由浏览器检查Access-Control-Allow-Origin 标头。 cURL 不运行这样的检查,任何其他服务器端软件(例如 NodeJS 或 Tomcat)也不运行。 这让我明白了很多:zemnmez.medium.com/…。任何为 curl 有效但不能获取的明显矛盾而苦苦挣扎的人,请阅读:) CORS 解决的真正问题是,没有它,任何域都可以从任何其他域请求任何资源,并且他们可以使用浏览器中已经存在的 cookie .所以他们可以请求gmail.com/account,如果您登录了 gmail,他们就会看到您的帐户页面。 CORS 阻止了这一点。 (不过,我不明白为什么浏览器不只是不发送 cookie 以及 CORS 不允许的请求。为什么要完全禁用整个请求?) 【参考方案1】:

如果您遇到 CORS 错误,则说明您做错了。这意味着您将 API 密钥暴露给宇宙。大线索!

相反,您可能希望使用商店中安装的应用程序进行 JS 调用进行调查。您可以为此使用应用代理。您安装的任何应用程序都可以访问您获得批准范围的任何 API 端点。因此,如果您的应用程序获准请求位置,则请求位置将返回给您。

简单!

【讨论】:

以上是关于简单的了解下 Fetch API 的工作原理的主要内容,如果未能解决你的问题,请参考以下文章

Fetch API - 重定向的用途:手册

无法使用 fetch API 获取数据

嗯,还在用Ajax嘛?Fetch了解一下呀

嗯,还在用Ajax嘛?Fetch了解一下呀

React Fetch:获取json结果但显示网络错误

如何在不使用 JQuery 的情况下使用 fetch API 以 JSON 格式发布表单数据?