文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Axios vs. fetch():哪个最适合 HTTP 请求?

2024-11-30 00:28

关注

但许多人高估了这个库。

fetch() API不但完全能够重现Axios的关键功能,而且还有随时可用于所有现代浏览器中的独特优势。

在本文中,我将按照基本语法、向后兼容性、响应超时、自动JSON数据转换、HTTP拦截器、下载进度、同时请求这些方面来比较fetch()和Axios,看看它们如何执行任务。

希望在本文结束时,大家对这两个API有了更深入的了解。

基本语法

在我们深入研究Axios更高级地功能之前,先与fetch()进行基本语法的比较。

下面是Axios如何将带有自定义请求头的[POST]请求发送到指定URL的代码:

// axios

const url = 'https://jsonplaceholder.typicode.com/posts'
const data = {
  a: 10,
  b: 20,
};
axios
  .post(url, data, {
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json;charset=UTF-8",
    },
  })
  .then(({data}) => {
    console.log(data);
});

与fetch()版本进行比较:

// fetch()

const url = "https://jsonplaceholder.typicode.com/todos";
const options = {
  method: "POST",
  headers: {
    Accept: "application/json",
    "Content-Type": "application/json;charset=UTF-8",
  },
  body: JSON.stringify({
    a: 10,
    b: 20,
  }),
};
fetch(url, options)
  .then((response) => response.json())
  .then((data) => {
    console.log(data);
  });

注意:

向后兼容性

Axios的主要卖点之一是其广泛的浏览器支持。

即使是像IE11这样的旧浏览器也可以毫无问题地运行Axios。这是因为它背后使用了XMLHttpRequest。

而fetch()仅支持Chrome 42+,Firefox 39+,Edge 14+和Safari 10.3+。

如果你使用Axios的唯一原因是向后兼容性,那么实际上并不需要HTTP库。而且,你可以将fetch()与polyfill一起使用,在不支持fetch()的web浏览器上实现类似的功能。

要使用fetch() polyfill,可以通过npm命令进行安装,如下所示:

npm install whatwg-fetch --save

然后,提出如下请求:

import 'whatwg-fetch'
window.fetch(...)

谨记,在有些旧浏览器中,可能还需要promise polyfill。

响应超时

在Axios中设置超时的简单性,是一些开发人员比fetch()更喜欢Axios的原因之一。

在Axios中,你可以使用配置对象的timeout属性来设置请求中止之前的毫秒数。

例如:

axios({
  method: 'post',
  url: '/login',
  timeout: 4000,    // 4 seconds timeout
  data: {
    firstName: 'David',
    lastName: 'Pollock'
  }
})
.then(response => {})
.catch(error => console.error('timeout exceeded'))

Fetch()通过AbortController接口提供类似的功能。

不过,它的代码不如Axios版本简单:

const controller = new AbortController();
const options = {
  method: 'POST',
  signal: controller.signal,
  body: JSON.stringify({
    firstName: 'David',
    lastName: 'Pollock'
  })
};  
const promise = fetch('/login', options);
const timeoutId = setTimeout(() => controller.abort(), 4000);

promise
  .then(response => {})
  .catch(error => console.error('timeout exceeded'));

代码使用AbortController.abort()构造函数创建AbortController对象,它允许我们稍后中止请求。

Signal是AbortController的只读属性,提供了一种与请求通信或中止请求的方法。

如果服务器在4秒内没有响应,则调用controller.abort(),终止操作。

自动JSON数据转换

如前所述,Axios在发送请求时会自动字符串化数据(当然你也可以覆盖默认行为并定义不同的转换机制)。

但是,当使用fetch()时,你必须手动执行此操作。

比较:

// axios
axios.get('https://api.github.com/orgs/axios')
  .then(response => {
    console.log(response.data);
  }, error => {
    console.log(error);
  });
// fetch()
fetch('https://api.github.com/orgs/axios')
  .then(response => response.json())    // one extra step
  .then(data => {
    console.log(data) 
  })
  .catch(error => console.error(error));

自动转换数据是一个不错的功能,但同样,这不是你不能用fetch()做的事情。

HTTP拦截器

Axios的主要功能之一是它能够拦截HTTP请求。

当你需要检查或更改从应用程序到服务器的HTTP请求时,使用HTTP拦截器非常方便,从服务器到应用程序亦是如此(例如,日志记录、身份验证或重试失败的HTTP请求)。

使用拦截器就不必为每个HTTP请求编写单独的代码。

在你想要为处理请求和响应设置全局策略时,HTTP拦截器非常有用。

以下是在Axios中声明请求拦截器的方法:

axios.interceptors.request.use(config => {
  // log a message before any HTTP request is sent
  console.log('Request was sent');

  return config;
});

// sent a GET request
axios.get('https://api.github.com/users/sideshowbarker')
  .then(response => {
    console.log(response.data);
  });

上面的代码中,axios.interceptors.request.use()方法用于定义发送HTTP请求之前要运行的代码。而axios.interceptors.response.use()用于拦截来自服务器的响应。

假设存在网络错误,那么通过响应侦听器,可以重试相同的请求。

默认情况下,fetch()不提供拦截请求的方法,但它的解决方法也并不复杂。

那就是覆盖全局fetch()方法并定义自己的拦截器,如下所示:

fetch = (originalFetch => {
  return (...arguments) => {
    const result = originalFetch.apply(this, arguments);
      return result.then(console.log('Request was sent'));
  };
})(fetch);

fetch('https://api.github.com/orgs/axios')
  .then(response => response.json())
  .then(data => {
    console.log(data) 
  });

下载进度

进度条在加载时非常有用,尤其是对于互联网速度较慢的用户。

以前,JavaScript程序员使用XMLHttpRequest.onprogress回调处理程序来实现进度指示器。

Fetch API没有onprogress处理程序。事实上,它通过响应对象的body属性来提供ReadableStream的实例。

以下示例表明如何使用ReadableStream在图像下载期间为用户提供即时反馈:

index.html

  
progress
script.js 'use strict' const element = document.getElementById('progress'); fetch('https://fetch-progress.anthum.com/30kbps/images/sunrise-baseline.jpg') .then(response => { if (!response.ok) { throw Error(response.status+' '+response.statusText) } // ensure ReadableStream is supported if (!response.body) { throw Error('ReadableStream not yet supported in this browser.') } // store the size of the entity-body, in bytes const contentLength = response.headers.get('content-length'); // ensure contentLength is available if (!contentLength) { throw Error('Content-Length response header unavailable'); } // parse the integer into a base-10 number const total = parseInt(contentLength, 10); let loaded = 0; return new Response( // create and return a readable stream new ReadableStream({ start(controller) { const reader = response.body.getReader(); read(); function read() { reader.read().then(({done, value}) => { if (done) { controller.close(); return; } loaded += value.byteLength; progress({loaded, total}) controller.enqueue(value); read(); }).catch(error => { console.error(error); controller.error(error) }) } } }) ); }) .then(response => // construct a blob from the data response.blob() ) .then(data => { // insert the downloaded image into the page document.getElementById('img').src = URL.createObjectURL(data); }) .catch(error => { console.error(error); }) function progress({loaded, total}) { element.innerHTML = Math.round(loaded/total*100)+'%'; }

在Axios中实现进度指示器更简单,尤其是在使用Axios进度条模块时。

首先,包含以下样式和脚本:

// the head of your HTML
    


// the body of your HTML
     
    
    
    

// add the following to customize the style

然后像这样实现进度条:

代码使用FileReaderAPI异步读取下载的图像。

readAsDataURL方法以Base64编码字符串的形式返回图像的数据,然后将其插入到img标记的src属性中以显示图像。

并发请求

为了同时发出多个请求,Axios提供axios.all()方法。

只需将请求数组传递给此方法,然后使用axios.spread()将响应数组的属性分配给单独的变量:

axios.all([
  axios.get('https://api.github.com/users/iliakan'), 
  axios.get('https://api.github.com/users/taylorotwell')
])
.then(axios.spread((obj1, obj2) => {
  // Both requests are now complete
  console.log(obj1.data.login + ' has ' + obj1.data.public_repos + ' public repos on GitHub');
  console.log(obj2.data.login + ' has ' + obj2.data.public_repos + ' public repos on GitHub');
}));

也可以使用内置的Promise.all()方法获得相同的结果。

将所有fetch请求作为数组传递给Promise.all()。接着使用async函数处理响应,如下所示:

Promise.all([
  fetch('https://api.github.com/users/iliakan'),
  fetch('https://api.github.com/users/taylorotwell')
])
.then(async([res1, res2]) => {
  const a = await res1.json();
  const b = await res2.json();
  console.log(a.login + ' has ' + a.public_repos + ' public repos on GitHub');
  console.log(b.login + ' has ' + b.public_repos + ' public repos on GitHub');
})
.catch(error => {
  console.log(error);
});

结论

Axios在紧凑的软件包中提供了一个易于使用的API,可满足大多数HTTP通信需求。

而web浏览器提供的fetch()方法则能完全重现Axios库的主要功能。

所以,是否加载客户端HTTP API取决于你是否习惯使用内置API。

编程快乐!

来源:前端新世界内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯