zl程序教程

您现在的位置是:首页 >  工具

当前栏目

Fetch vs Axios

vs Axios fetch
2023-06-13 09:11:16 时间

原文链接:https://meticulous.ai/blog/fetch-vs-axios/[1]

作者:Ibas Majid[2]

正文从这开始~

当我们构建的应用程序需要我们进行网络请求时,无论是对我们的后端还是对第三方API,我们都使用Axios和Fetch这样的HTTP客户端来执行此类请求。

在本篇指南中,我们将会介绍Axios和Fetch,并对它们进行比较,以便让我们做出明智的决定去选择。

快速概览

Fetch API是一个接口,暴露了一个叫做fetch()的方法,用于发出网络请求。它内置于现代浏览器中,因此不需要安装。它也可以作为node.js的一个实验性功能使用。

Axios是一个第三方库,我们可以通过CDN将其添加到我们的项目中,也可以通过包管理器来安装,比如说npm或者yarn。Axios可以运行在浏览器或者node.js环境中。

Fetch和Axios都是基于promise的HTTP客户端。这意味着当我们使用它们来创建网络请求时,它们会返回一个resolve或者rejectpromise

安装Axios

如果我们在node.js环境中使用axios,我们可以使用以下的安装方法:

使用NPM安装:

npm install axios

使用Yarn安装:

yarn add axios

将它们导入到项目中:

import axios from "axios";

如果我们在浏览器中使用Axios,可以使用CDN引入:

<script src="<https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js>"></script>

你可以在这里[3]阅读所有安装Axios的方式。现在一切准备就绪,接下来开始比较它们。

比较Fetch和Axios的特性

让我们从语法开始。

语法

Fetch接收两个参数。第一个参数是我们要获取的资源的URL。第二个参数是可选参数,它是一个对象,包含发出请求的配置项。基于此,具体语法如下:

如果没有指定配置项,会默认发出GET请求:

fetch(url)

如果指定配置项,我们可以为请求定义一些自定义设置,包括:

fetch(url, {
  method: 'GET', // other options: POST, PUT, DELETE, etc.
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({}),
})

Axios的语法更加简洁,但是有很多不同的调用方式:

axios(url, {
  // configuration options
})

我们也可以像这样来附加HTTP方法:

axios.get(url, {
  // configuration options
})

和fetch方法一样,我们也可以忽略axios中的HTTP方法,默认为GET,就像这样:

axios(url)

同样地,我们可以使用第二个参数,为请求定义一些自定义设置:

axios(url, {
  method: 'get', // other options: post, put, delete, etc.
  headers: {},
  data: {},
})

也可以这么写:

axios({
  method: 'get',
  url: url,
  headers: {},
  data: {},
})

现在让我们下研究Axios和fetch处理响应的不同方式。

处理JSON数据

在下面的例子中,我们对一个名为JSONPlaceholder的REST API执行了一个GET请求。使用fetch和Axios获取待办事项列表,并比较两者的差异。

使用Fetch API,我们的代码如下所示:

const url = "<https://jsonplaceholder.typicode.com/todos>";

fetch(url)
  .then(response => response.json())
  .then(console.log);

在控制台中打印的结果如下所示:

fetch结果.png

fetch() 返回了一个promise,其响应由.then()方法来处理。此时,我们没有得到我们所需要的JSON数据格式,因此,我们对响应对象调用.json()方法。这将返回另一个promise,该promise用JSON形式来解决(resolved)数据。所以一个典型的fetch请求包含两个.then()调用。

然而,如果我们使用axios来执行相同的数据获取,我们会有以下代码:

const url = "<https://jsonplaceholder.typicode.com/todos>";

axios.get(url)
.then(response => console.log(response.data));

在Axios中,响应数据默认为JSON。响应数据始终在响应对象的data属性上可用。

我们可以通过在配置项中指定responseType,来覆盖默认的JSON数据类型,就像这样:

axios.get(url, {
  responseType: 'json' // options: 'arraybuffer', 'document', 'blob', 'text', 'stream'
})

自动字符串化

现在,让我们试着使用JSONPlaceholder[4] API来发送数据。

我们需要序列化我们的数据到JSON字符串中。当我们使用POST方法将JS对象发送到API,Axios会自动将数据字符串化。

以下代码使用Axios来执行一个post请求:

const url = "<https://jsonplaceholder.typicode.com/todos>";

const todo = {
  title: "A new todo",
  completed: false
} 

axios.post(url, {
  headers: {
    'Content-Type': 'application/json',
  },
  data: todo
})
.then(console.log);

当我们使用axios来发送post请求,我们把要发送的数据作为请求体分配给data属性。我们也可以设置Content-Type头部。默认情况下,axios设置Content-Type 值为application/json

让我们瞧一瞧响应对象:

axios响应对象.png

响应数据位于response.data ,就像这样:

.then(response => console.log(response.data));

如果我们使用Fetch API,我们必须手动调用JSON.stringify()来字符串化对象。然后将其赋值到请求对象的data属性上。

const url = "<https://jsonplaceholder.typicode.com/todos>";

const todo = {
  title: "A new todo",
  completed: false
};

fetch(url, {
  method: "post",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify(todo)
})
  .then((response) => response.json())
  .then((data) => console.log(data))

使用Fetch,我们还必须显式地设置Content-Type值为application/json

错误处理

fetch和axios都返回一个被解决(resolved)或被拒绝(rejected)的promise。当promise被拒绝时,我们可以使用.catch() 来处理错误。与Fetch的方法相比,使用axios处理错误的方式更简洁。

从axios开始,使用.catch()来处理典型错误。代码如下所示:

const url = "<https://jsonplaceholder.typicode.com/todos>";

axios.get(url)
  .then((response) => console.log(response.data))
  .catch((err) => {
    console.log(err.message);
  });

如果状态码超出2xx的范围,Axios的promise将会拒绝(reject)。我们可以通过检查err对象是否包含responserequest属性来确定关于错误的更多信息。比如说:

.catch((err) => {
  // handling error
  if (err.response) {
    // Request made and server responded

    const { status, config } = err.response;

    if (status === 404) {
      console.log(`${config.url} not found`);
    }
    if (status === 500) {
      console.log("Server error");
    }
  } else if (err.request) {
    // Request made but no response from server
    console.log("Error", err.message);
  } else {
    // some other errors
    console.log("Error", err.message);
  }
});

error对象上的response属性表示客户端收到了一个状态代码在2xx范围之外的错误响应。error对象上的request属性表示发出了一个请求,但客户端没有收到响应。否则,如果没有responserequest 属性,则表示在设置网络请求时发生错误。

如果我们收到404错误或任何其他HTTP错误,Fetch将不会拒绝一个promise。Fetch只有在网络请求失败时拒绝promise。所以我们必须在.then子句中手动处理HTTP错误。

让我们瞧一瞧下面代码:

const url = "<https://jsonplaceholder.typicode.com/todos>";

fetch(url) 
  .then((response) => {
    if (!response.ok) {
      throw new Error(
        `This is an HTTP error: The status is ${response.status}`
      );
    }
    return response.json();
  })
  .then(console.log)
  .catch(err => {
    console.log(err.message);
  });

response代码块中,我们检查了responseok属性是否是false,然后我们抛出了一个自定义错误,并在.catch代码块中进行处理。

我们可以像这样查看响应对象上可用的方法:

.then(console.log)

响应对象可用方法.png

上面的截图是一个成功的fetch。在我们碰到一个错误的URL端点的情况下,okstatus属性将分别变成false404,然后我们抛出一个错误,.catch()子句将显示我们自定义的错误信息。

响应超时/取消请求

让我们看看HTTP客户端针对HTTP请求,如何处理响应超时。对于Axios,我们可以在配置对象中添加一个timeout属性,并指定请求终止前的时间,单位为毫秒。

在下面的代码片段中,我们的目标是在请求时间超过4秒时终止请求,然后在控制台中打印一个错误。

const url = "<https://jsonplaceholder.typicode.com/todos>";

axios.get(url, {
  timeout: 4000, // default is `0` (no timeout)
})
  .then((response) => console.log(response.data))
  .catch((err) => {
    console.log(err.message);
  });

在Fetch中取消请求,我们可以使用AbortController[5]接口。参考下面的用法:

const url = "<https://jsonplaceholder.typicode.com/todos>";

const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => controller.abort(), 4000);

fetch(url, {
  signal: signal
})
  .then((response) => response.json())
  .then(console.log)
  .catch((err) => {
    console.error(err.message);
  });

我们首先创建了一个controller对象,获得了对signal对象和abort()方法的访问权。然后通过配置选项将signal对象传递给fetch()。有了上述配置,只要调用abort方法,fetch请求就会终止。正如我们看到的,在setTimeout函数的帮助下,如果服务器在4秒内没有响应,fetch操作就会终止。

性能

既然两者都是基于promise的,那么他们不应引起任何性能问题。然而,我们仍然可以使用measurethat.net[6]来衡量它们的性能。

在使用在线工具进行连续测试后,我们得到如下结果:

性能测试.png

如上所述,原生Fetch比axios略快。这是无关紧要的,因为两个客户端都是异步的。

浏览器支持

Axios和Fetch在现代浏览器中得到广泛支持。对于较老环境比如IE11,不支持ES6 Promise语法。我们必须使用polyfill[7]来解决兼容性问题。特别是Fetch,我们将添加另一个polyfill[8]来支持在旧浏览器[9]中的实现。

总结

在本指南中,我们讨论了Fetch和axios,并在实际场景中对它们进行了比较。最后,你在项目中选择什么取决于你的个人偏好和易用性。

参考资料

[1]

https://meticulous.ai/blog/fetch-vs-axios/: https://meticulous.ai/blog/fetch-vs-axios/

[2]

Ibas Majid: https://ibaslogic.com/

[3]

这里: https://axios-http.com/docs/intro

[4]

JSONPlaceholder: https://jsonplaceholder.typicode.com/

[5]

AbortController: https://developer.mozilla.org/en-US/docs/Web/API/AbortController

[6]

measurethat.net: https://www.measurethat.net/

[7]

使用polyfill: https://github.com/stefanpenner/es6-promise

[8]

添加另一个polyfill: https://github.com/github/fetch

[9]

旧浏览器: https://caniuse.com/fetch