axios请求-基本使用
前言
要了解axios,需要先了解Ajax(Asynchronous JavaScript And XML 即异步 JavaScript 和 XML)请求。简单来说,Ajax的作用为从服务端获取数据,实现页面的局部刷新。
一般请求和Ajax请求:
- 一般请求:浏览器会直接显示响应体数据,会自动刷新整个网页或跳转页面。
- Ajax请求:浏览器不会对整个界面进行刷新,得到数据后,对部分的元素进行刷新。
显然,Ajax请求减少了页面频繁刷新的次数,使用者的体验更加丝滑。Axios也是用来发送Ajax请求。
Axios 是一个流行的基于 Promise 的 HTTP 请求库,用于在浏览器和 Node.js 中进行 HTTP 请求。它提供了简单易用的 API,可以发送各种类型的请求(如 GET、POST、PUT、DELETE等),并处理响应数据,Axios 在前端工程化项目中有 99% 的概率会被优先选择。
演示API文档
后续演示使用的api文档,api文档的制作可以参考apiDoc。
请求url | 方式 | 参数 |
---|---|---|
http://127.0.0.1:5000/persons | GET | 无需参数 |
http://127.0.0.1:5000/person | GET | query参数 id:String 人员唯一标识符 |
http://127.0.0.1:5000/filter/age | GET | parms参数 age:int 人员年龄 |
http://127.0.0.1:5000/person | POST | 请求体参数 name:string 名字 age:number 年龄 |
http://127.0.0.1:5000/person | PUT | 请求体参数 id:string 人员唯一标识符 name:string 人员名字 age:number 人员年龄 |
http://127.0.0.1:5000/person | DELETE | 请求体参数: id:string 人员唯一标识符 |
模拟服务端使用的代码:
1 | import Koa from "koa"; |
初始数据为
1 | [ |
基本使用
引入cdn
1 | <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.7.5/axios.min.js"></script> |
创建一个页面,并获取所有人的数据。地址为/persons
1 |
|
axios有两种写法:
- 简写形式:
axios.get(url)
- 一般形式:
axios({method:"GET",url:url})
1 | async function getData() { |
axios返回的是一个Promise
对象(也可以使用.then()
和.catch()
的写法,推荐异步async写法),其中包含请求的很多数据,我们需要的数据在data
字段中。
按照文档(也可参照上图),服务器返回的内容也是一个对象,其中包含多种信息,真实的数据在返回对象的data字段中。所以,如果要获取到真实数据,需要使用result.data.data
1 | async function getData() { |
这样就可以得到真实的数据。
拦截器
拦截器是用来对请求和响应进行过滤、预处理的操作函数。具体原理图如下所示
请求拦截器
考虑到api文档中所有的请求都以http://127.0.0.1:5000
作为开头,因此可以考虑用请求拦截器优化这个行为。
参考上文拦截器的原理示意图,使用拦截器interceptors
时,我们需要传入本次请求的信息config
,并需要从拦截器中返回处理后的config
,否则就会请求错误。
1 | // 请求拦截器 |
使用baseURL
设置后,所有的请求都会自动加上这个前缀,避免了多次重复书写的麻烦。
请求拦截器config的设置,可以在请求配置中找到。
响应拦截器
每次获取到数据都需要result.data.data
,第一个data是由于axios本身造成的,且每次操作都一致,因此考虑使用相应拦截器来优化。
严格来说,请求是没有失败一说的,但是响应是有可能失败的。对与响应拦截器,还提供了一个回调函数供给出错处理使用。
1 | // 相应拦截器 |
这样处理后,每次只需根据api文档的要求获取相应对象的字段即可,展示在上述代码中即为只需写一个data。
另外,使用await
关键字有一个弊端,如果响应失败,且在拦截器中返回了具体的内容的话,那么会出现完全矛盾的输出。修改请求为/person2
(实际并不存在这个api),控制台得到如下的结果。
即便是响应失败了,还是让最后打印数据的语句执行了,这说明await
得到了一个非reject
的回应(代码返回的是err
),因此程序正常执行了下去。可想而知,需要在错误处理和返回值的地方下手解决。
最简单的方法就是不写错误响应的回调函数,这样await
迟迟等不来结果,就会抛出Uncaught (in promise)
的错误。但是这种方法无法得到任何语义化的提示,因此不是很推荐。
接下来介绍三种常用的处理方法。
使用
try
andcatch
进行错误捕获。(在拦截器return err
的情况下才有效)1
2
3
4
5
6
7
8
9
10async function getData() {
try {
// 简写形式
let result = await axios.get('/persons2')
console.log("响应成功:", result.data);
} catch (error) {
console.log("响应失败", error);
}
}Promise.reject 在拦截器中返回
reject
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// 添加响应拦截器
axios.interceptors.response.use(
res=>{
// 对响应数据做点什么
console.log("请求成功");
return res.data
},
err=>{
// 对响应错误做点什么
console.log("请求失败");
return Promise.reject(err)
}
)
async function getData() {
// 简写形式
let result = await axios.get('/persons2')
console.log("响应成功:",result.data);
}中断Promise
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// 添加响应拦截器
axios.interceptors.response.use(
res=>{
// 对响应数据做点什么
console.log("请求成功");
return res.data
},
err=>{
// 对响应错误做点什么
console.log("请求失败");
return new Promise(()=>{})
}
)
async function getData() {
// 简写形式
let result = await axios.get('/persons2')
console.log("响应成功:",result.data);
}
全局axios配置
除了使用相应拦截器来规定默认的请求条件,也可以通过修改axios的全局配置项来实现。
1 | axios.defaults.baseURL = 'http://127.0.0.1:5000' |
这样和前文中相应拦截器的效果是相同的,不同在于修改config
的时机。
interceptors.request
- 发出请求后在拦截器中修改,属事后修改。axios.defaults
- 在发出请求前就已经配置,属事前修改。
- 后续创建的axios对象的设置会继承
axios.defaults
的值(非引用)。- 全局是针对只有一个axios的情况,新创建的axios不会因默认
axios.default
的修改受到影响。
请求类型和请求参数
常用的请求类型:
类型 | 常用领域 | axios形式 |
---|---|---|
GET | 查 | axios#get(url[, config]) |
POST | 增 | axios#post(url[, data[, config]]) |
PUT | 改 | axios#put(url[, data[, config]]) |
DELETE | 删 | axios#delete(url[, config]) |
请求参数类型:
- query参数(查询字符串)
- params参数(路径传参)
- 请求体参数(json编码,urlencoded编码)
GET请求
GET请求多用于查询场景。
query参数
以id
获取数据为例子。地址为/person
1 | async function getData() { |
需要注意的是,设置query
参数的名称为params
,这是因为params
本身就有参数的意思,最终可以得到相应的结果
1 | { |
如果替换为不存在的id
,那么不会返回data
字段
1 | { |
使用配置项传参,实际上是axios自动将
params
和baseURL
拼接好。在控制台可以看到具体的请求url。
params参数
以age
获取数据为例子。地址为/filter/age
params参数也称为路径传参。需要注意的是,params传参不存在配置项的写法。
1 | async function getData() { |
得到的返回结果如下:
1 | { |
如果输入age
匹配不到,不会返回data
字段
1 | { |
POST请求
POST请求主要用于添加数据。以添加用户为例子,地址为/person
。
使用的是请求体参数,有两种格式:
- json格式 -
{name:"强哥",age:28}
(自动解析) - urlencoded格式 -
"name=强哥&age=28"
简写形式
1 | async function addData() { |
完整形式
1 | async function addData() { |
两种格式都能够成功添加
1 | { |
在控制台的负载面板中可以看到上传的请求体参数。
查看所有人,可以看到人数加1,且能够看到添加的数据。
1 | { |
使用json作为请求体参数时,由于json不属于简单请求Content-Type的范围(urlencoded在范围内),因此请求为复杂请求,如果服务端没处理好,很有可能会遇到跨域问题。如果请求体参数以json格式发送,在开发者工具的网络面板中,可以看到预检请求(OPTIONS),具体的原因与解决方法参考前端-跨域&解决方案。
PUT请求
PUT请求主要用于更新数据。以修改信息为例。地址为/person
完整形式
1 | async function updateData() { |
简写形式
1 | async function updateData() { |
控制台得到的返回为:
1 | { |
获取所有人数据,证实已被修改。
1 | { |
DELETE请求
PUT请求主要用于删除数据。以珊瑚信息为例。地址为/person
。
简写形式
1 | async function delData() { |
完整形式
1 | async function delData() { |
返回的结果如下
1 | { |
查看原始数据,发现确实少了id
为d93d5860的数据
1 | { |
创建axios
假设需要访问多个不同的api源。除了http://127.0.0.1:5000
,我们还需要访问另一个热搜榜的apihttps://tenapi.cn/v2
。那么就需要多个axios对象。
1 | const axios2 = axios.create({ |
上述代码创建了一个新的axios
对象用于获取热搜数据,将其baseURL设置为https://tenapi.cn/v2
,而保留原本的axios用于本地http://127.0.0.1:5000
的请求。这样两者就不会发生冲突。
注意:
创建的axios会继承
axios.defaults
里的所有配置项,因此需要单独重新设定配置项(否则配置项完全相同)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 axios.defaults.baseURL = 'http://127.0.0.1:5000'
axios.defaults.timeout = 5000
// 未配置的axios实例 与默认axios的配置完全相同
const axios2 = axios.create()
function isEqual(obj1, obj2) {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return { result: false, message: "长度不相等" };
}
for (let key of keys1) {
if (!obj2.hasOwnProperty(key)) {
return { result: false, message: "缺少属性" };
}
if (
typeof obj1[key] === "object" &&
obj1[key] !== null &&
typeof obj2[key] === "object" &&
obj2[key] !== null
) {
const subResult = isEqual(obj1[key], obj2[key]);
if (!subResult.result) {
return subResult;
}
} else if (obj1[key] !== obj2[key]) {
return { result: false, message: "值不相等" };
}
}
return { result: true, message: "完全相同" };
}
console.log(isEqual(axios.defaults, axios2.defaults)); // { result: true, message: "完全相同" }新创建的axios没有取消请求和批量发请求的方法,其它语法完全一致。
批量发送请求
可以将多个axios对象放在一个列表中,使用axios.all()
一次性发出全部请求。
1 | axios.defaults.baseURL = 'http://127.0.0.1:5000' |
返回的是装有所有响应请求对象的数组,如下所示(为了展示删除了对象的一些属性)
1 | [ |
Axios.all()
基于promise.all()
,所有的都是成功的回调才会返回数据,如果有一个失败的回调,就会得到reject
的状态,抛出Uncaught (in promise)
错误。
出现
Uncaught (in promise)
的主要原因是Promise
返回的reject
状态没有被处理,系统自动抛出错误。解决方法可以参考上文响应拦截器的正文部分。