深入理解fetch api(1) --基础用法

相信不少最近刚学习前端的小伙伴,使用的都是axios请求库。诚然,axios是一个高度封装的http请求库,易于上手使用,但是随着学习的深入,其较大的包体积和不适合长时间处理的问题日益显现,因此,笔者将目光投向了主流的fetch api, 也就有了这篇文章的主题

请求用法

这是最基础的fetch请求,注意,未声明请求方式的情况下,fetch发送的是get请求
1
fetch('https://api.example.com/data')
比如我们需要发送一个post请求,就需要使用fetch api的第二个参数
1
2
3
fetch('https://api.example.com/data',{
method: 'post'
})
如果后端使用了jwt鉴权,我们需要将token放入请求头中,我们就可以这么操作
1
2
3
4
5
6
fetch('https://api.example.com/data',{
method: 'post',
headers: {
Authorization: 'your_token'
}
})
实际操作中, 我们需要向后端传递相关参数
与axios不同,axios可以直接添加params:{}传递参数,fetch api不原生支持params选项,所以我们需要通过手动拼接url的方式传递params参数
例如我们现在有这样的一个对象字面量
1
2
3
4
const data = {
target: 1,
from: 2,
}
我们可以使用javascript原生的URLSearchParams构造函数将其转化为查询字符串
使用方法
1
const dataParams = new URLSearchParams(data).toString()
输出结果
1
target=1&from=2
然后我们可以使用ES6新特性中的模板字面量拼接url
1
2
3
4
5
6
fetch(`https://api.example.com/data?${dataParams}`,{ //注意这里是反引号 `` 代表模板字面量 可以使用插值 ${}
method: 'post',
headers: {
Authorization: 'your_token'
}
})
这样我们就成功传递了params参数
fetch api在传递body参数时与axios大同小异,但是多了一手动序列化的流程, 这里我们借用一下上面提到的data对象来演示
1
2
3
4
5
6
7
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data) // 手动序列化
});
这段代码中,我们就能很直观的看出与axios的区别,首先是请求头中'Content-Type'声明了请求体中传递的是JSON格式的数据,然后通过JS原生的JSON对象中的stringfy方法转化为json格式的字符串,这两个步骤就是上文提到的手动序列化,这样我们也就达成了传递body参数的目的

处理返回

说完了发送请求,我们自然还要研究如何处理,不同于axios近乎傻瓜式的用法,fetch需要稍微复杂的处理
fetch返回的是一个promise对象,最终会被解析为一个response对象,例如下面的代码
1
2
3
4
5
6
7
8
9
10
11
12
const fetchPromise = fetch('https://api.example.com/data',{
method: 'post',
headers: {
Authorization: 'your_token'
}
})

fetchPromise.then(
(response) => {
console.log(response)
}
)
response的结构为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
response {
body: ReadableStream,
bodyUsed: false,
headers: Headers {
"content-type": "application/json; charset=utf-8",
"authorization": "your_token"
},
ok: true,
redirected: false,
status: 200,
statusText: "OK",
type: "basic",
url: "https://api.example.com/data"
}
我们可以显式的获取一些状态,比如说状态码和ok(是否访问成功), 以及访问头
但是注意,body是一个流,不能一次性获取所有内容,这里涉及到另一个异步操作,下面给出具体的代码
1
2
3
4
5
6
fetchPromise.then(response => {
return response.json(); // 解析 JSON 数据 注意 这是一个异步操作 所以需要一个.then来读取
})
.then(data => {
console.log(data); // 指向response.json()
}
这样我们就可以读取后端返回的内容了,但是还得注意的是,除非网络请求本身出现问题(无法连接到服务器等),fetch不会主动的抛出一个错误,即使是请求失败(404和500),也会返回一个成功的promise,这里就需要我们自己来从处理error, 下面给出简单的代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
fetchPromise
.then(response => {
if (!response.ok) {
throw new Error('网络响应错误,状态码:' + response.status); //访问失败,抛出错误
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch((error) => {
console.error('请求失败:', error); // 打印错误信息
});
上述代码中,throw能让控制流转到最近的catch模块, 而new Error构造函数能创建一个错误对象,通过这种方式,我们可以成功的处理未捕捉到的请求错误问题



综上即是fetch api的基础用法,但是实际的开发过程中,就算是高度封装的axios,我们也要进行进一步的封装以提升代码可读性,更别说是更加轻量化的fetch。下一篇博客,笔者将会以自己的项目为例来给出fetch的一套简易封装方案

未完待续…


深入理解fetch api(1) --基础用法
https://imjh.xyz/2024/10/20/fetch_api/
Author
弓弦叶
Posted on
October 20, 2024
Licensed under