当我们制做web应用时,我们通常使用Axios
和Fetch
等客户端来执行网络请求。 本文将介绍并表Axios
和Fetch
,以便在实际应用做出正确的选择。
Axios
和Fetch
概述
Fetch API
是一个提供了fetch()
方法的用于发送网络请求的接口,它内置于现代浏览器中,因此无需安装。Axios
是一个第三方库,我们可以通过cdn或包管理器安装使用它,Axios
可以在浏览器或node.js
中运行。
Fetch
和axios
都是基于promise
的HTTP客户端,这意味着当使用它们发出网络请求时,它们会返回一个resolve
或reject
的promise
。
安装axios
如果我们是在node.js
环境下使用axios
,我们可以使用以下任何一种方法安装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>
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: {},
})
处理JSON 数据
在下面的示例中,我们使用fetch
和Axios
执行GET请求,以获取todos项的列表,并比较它们之间的差异。 使用Fetch API,我们的代码如下所示:
const url = "https://jsonplaceholder.typicode.com/todos";
fetch(url)
.then(response => response.json())
.then(console.log);
控制台中的结果如下所示:
fetch()
返回一个promise
,在.then
方法里面处理,此时,我们还没有获得所需要的json格式的数据,所以在response对象上调用.json()
方法,这将返回另一个以json格式数据resolve
的promise
,所以fetch
请求包含两个promise
。
但是,如果我们使用Axios执行相同的请求,我们有以下代码:
const url = "https://jsonplaceholder.typicode.com/todos";
axios.get(url)
.then(response => console.log(response.data));
对于Axios,响应数据默认为JSON。响应数据在response
对象的data
属性上。
我们可以通过在配置项中指定responseType来覆盖默认的JSON数据类型,如下所示:
axios.get(url, {
responseType: 'json' // options: 'arraybuffer', 'document', 'blob', 'text', 'stream'
})
自动字符串化
当我们用post方法向api接口发送js对象时,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
。 让我们来看一下响应数据:
响应数据在response.data
上:
.then(response => console.log(response.data));`
如果我们使用Fetch API,我们必须使用JSON.stringify()
手动字符串化对象,然后将其分配给请求主体。
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
被rejected
时,我们可以使用.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对象是否包含response
或request
属性来获取有关错误的更多信息,如下所示:
.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属性表示发出了请求,但客户端没有收到响应。否则,如果没有请求或响应属性,则说明出现网络错误。
如果出现404错误或其他HTTP错误,Fetch不会reject promise。Fetch仅在网络出现故障时reject 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);
});
在响应块中,我们检查响应的ok状态是否为false,然后抛出一个在中处理的自定义错误。 我们可以看看响应对象上可用的方法,如下所示:
上面的屏幕截图是成功的fetch。在遇到错误的URL地址的情况下,ok和status属性将分别变为false和404,我们抛出一个错误,因此.catch()
子句将显示自定义错误消息。
响应超时/取消请求
让我们看看这些HTTP客户端如何处理HTTP请求的响应超时。使用Axios,我们可以在配置对象中添加超时属性,并以毫秒为单位指定请求终止前的时间。 在下面的代码片段中,我们的目标是,如果请求超过四秒钟的时间,就终止请求,然后在控制台中记录错误。
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接口。请参见下面的用法:
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);
});
我们从创建一个控制器对象开始,并获得了对signal对象和abort()
方法的访问权。然后,我们通过配置选项将signal对象传递给fetch()。这样,只要触发了abort方法,fetch请求就会终止。我们可以看到,在setTimeout函数的帮助下,如果服务器在四秒钟内没有响应,操作就会终止。
效率表现
由于Fetch和axios都是基于promise
的,因此它们不应该导致任何性能问题。然而,我们仍然可以使用measurethat.net来衡量他们的表现。我们得到以下结果:
如上所述,本机获取速度略快于axios。这是无关紧要的,因为两者都是异步的。
浏览器支持
Axios和Fetch在现代浏览器中得到广泛支持。对于像IE 11这样不支持ES6 promise的旧环境,对于Fetch,我们还需要添加一个polyfill来支持旧浏览器。
总结
我们讨论了Fetch和axios,并使用真实场景对它们进行了实际比较。最后,你在项目中选择什么取决于你的个人喜好和易用性。
measurethat.net/")来衡量他们的表现。我们得到以下结果:
[外链图片转存中…(img-DdkCA7wY-1653010293120)]
如上所述,本机获取速度略快于axios。这是无关紧要的,因为两者都是异步的。
浏览器支持
Axios和Fetch在现代浏览器中得到广泛支持。对于像IE 11这样不支持ES6 promise的旧环境,对于Fetch,我们还需要添加一个polyfill来支持旧浏览器。
总结
我们讨论了Fetch和axios,并使用真实场景对它们进行了实际比较。最后,你在项目中选择什么取决于你的个人喜好和易用性。