Axios概述
- axios是一个基于Promise的http请求库
- 可以用于浏览器和node.js,也就是说axios可以用于客户端和服务器端。
- 不支持IE8以下的浏览器
Axios特性
- 支持Promise API
- 拦截请求和响应,即可以请求前和响应前做一些操作(比如说在请求头添加自定义的请求头)
- 转换请求数据和响应数据,比如说在请求时对敏感信息进行加密,在响应时对敏感信息进行解密
- 取消请求
- 自动转换JSON数据
- 客户端支持防御CSRF(跨站请求伪造)
Axios基础用法
axios返回的数据格式:
常见请求方法
get请求
// 方式1
axios.get('/data.json').then(data => {
console.log(data);
});
// 方式2
axios({
method: 'GET',
url: '/data.json'
}).then(data => {
console.log(data);
});
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
带参数的get请求,参数会以查询字符串的形式拼接在请求url后面。
// http://localhost:8080/data.json?id=12&name=lisi
axios.get('/data.json', {
params: {
id: 12,
name: 'lisi'
}
}).then(data => {
console.log(data);
})
axios({
method: 'GET',
url: '/data.json',
params: {
id: 12,
name: 'lisi'
}
}).then(data => {
console.log(data);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
post请求
post请求的数据格式有两种:
- form-data:表单提交,一般用于文件/图片上传
- application/json:大多数情况都是使用这种数据格式
const data = {
id: 12,
name: 'lisi'
};
axios.post('/create', data).then(data => {
console.log(data);
});
axios({
method: 'post',
url: '/create',
data
}).then(data => {
console.log(data);
});
// formData格式的post请求
const formData = new FormData();
for (const key in data) {
if (data.hasOwnProperty(key)) {
formData.append(key, data[key]);
}
}
axios.post('/create', formData).then(data => {
console.log(data);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
需要注意:post请求的请求头中会比get请求多处一个字段:Content-Type: application/json;charset=UTF-8
。
put请求
axios.put('/update', data).then(data => {
console.log(data);
});
1
2
3
2
3
patch请求
axios.patch('/update', data).then(data => {
console.log(data);
})
1
2
3
2
3
需要注意:post、put、patch三个方法用法很类似,只不过从规范上来将作用不同。
delete请求
// http://localhost:8080/remove?id=12
axios.delete('/remove', {
params: { // params是以查询字符串的形式拼接参数,请求头中没有Content-Type
id: 12
}
}).then(data => {
console.log(data);
})
axios.delete('/remove', {
// Content-Type: application/json;charset=UTF-8
data: {
id: 12
}
}).then(data => {
console.log(data);
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
并发请求
并发请求:同时进行多个请求,并统一处理返回值。
axios.all([
axios.get('/data.json'), // 按照在数组中位置依次发送请求
axios.get('/test.json')
]).then(
axios.spread((dataRes, testRes) => {
console.log(dataRes);
console.log(testRes);
})
);
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Axios进阶用法
Axios实例
// axios实例
let instance = axios.create({
baseURL: 'http://localhost:8080', // 请求域名,基本地址
timeout: 1000, // 请求超时时长
url: '/data.json', // 请求路径
method: 'get', // 请求方法
headers: { // 设置请求头
token: ''
},
params: {}, // 请求参数拼接在url
data: {} // 请求参数放在请求体中
});
// baseURL会被拼接在/data.json前面
instance.get('/data.json', data => {
console.log(data);
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Axios配置
// 1. axios全局配置
axios.defaults.timeout = 1000;
axios.defaults.baseURL = 'http://localhost:8080';
// 2. axios实例配置
let instance = axios.create();
instance.defaults.timeout = 3000; // 这里不设置的话,实例默认使用全局中的配置
instance.defaults.baseURL = 'http://localhost:8090';
// 3. axios请求配置
instance.get('/data.json', {
timeout: 4000
});
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
优先级:axios请求配置 > axios实例配置 > axios全局配置。
// 实际开发
// 有两种请求接口
// http://localhost:8080
// http://localhost:8081
const instance = axios.create({
baseURL: 'http://localhost:8080',
timeout: 1000
});
const instance2 = axios.create({
baseURL: 'http://localhost:8081',
timeout: 3000
});
// baseURL,timeout,url,method,params
instance.get('/dataList', {
params: {
id: 12
}
}).then(data => {
console.log(data);
});
// baseURL,timeout: 5000,url,method
instance2.get('/userList', {
timeout: 5000 // 覆盖instance2中设置的timeout
}).then(data => {
console.log(data);
});
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
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
Axios拦截器
// 拦截器:在请求或响应被处理前进行拦截
// 分为请求拦截器和响应拦截器
// 请求拦截器
axios.interceptors.request.use(config => {
// 在发送请求前做些事情
return config;
}, err => {
// 在请求错误的时候做些事情
// 请求没有到达服务器
return Promise.reject(err);
});
// 响应拦截器
axios.interceptors.response.use(res => {
// 请求成功对响应数据做处理
return res;
}, err => {
// 在响应错误的时候做些事情
return Promise.reject(err);
});
// 取消拦截器(了解)
const customInterceptors = axios.interceptors.request.use(config => {
config.headers = {
auth: true
};
return config;
});
// 对上述定义的拦截器进行取消
axios.interceptors.request.eject(customInterceptors);
// 例子:登录状态: token
let instance = axios.create({});
// 在实际开发中一般是个实例设置拦截器,如果直接给给axios设置的话会造成污染,因为axios是全局的。
// 可以用instance来访问需要登录的接口
instance.interceptors.request.use(config => {
config.headers.token = 'token';
return config;
});
// 可以用instance2来访问不需要登录的接口
let instance2 = axios.create({});
// 实例开发举例:在请求前打开弹窗,请求后取消弹窗
const instance_phone = axios.create({});
instance_phone.interceptors.request.use(confirm => {
$('#dialog').show();
return config;
});
instance_phone.interceptors.response.use(res => {
$('#dialog').hide();
return res;
});
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
39
40
41
42
43
44
45
46
47
48
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
39
40
41
42
43
44
45
46
47
48
取消请求
// 错误处理:在请求错误时进行的处理
axios.interceptors.request.use(config => {
return config;
}, err => {
return Promise.reject(err);
});
axios.interceptors.response.use(res => {
return res;
}, err => {
// 请求和响应拦截器中的错误都会被catch捕获到
return Promise.reject(err);
});
axios.get('/data2.json').then(res => {
console.log(res);
}).catch(err => {
console.log(err);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在实际开发过程中,一般在拦截器中添加统一的错误处理,对于特殊接口在catch单独处理。
const instance = axios.create({});
instance.interceptors.request.use(config => {
return config;
}, err => {
// 客户端请求错误,4xx
$('#errorDialog').show();
setTimeout(() => {
$('#errorDialog').hide();
}, 3000);
return Promise.reject(err);
});
instance.interceptors.response.use(config => {
return config;
}, err => {
// 服务端响应错误,5xx
$('#errorDialog').show();
setTimeout(() => {
$('#errorDialog').hide();
}, 3000);
return Promise.reject(err);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Axios封装
- 第一步:将请求的api统一放到一个单独的js文件中,方便管理
- 第二步:对请求方法进行统一格式的封装,包括参数传递、添加统一加载提示、在headers添加统一的token鉴权处理、错误处理。
const CONTACT_API = {
// 获取联系人列表
getContactList: {
method: 'get',
url: '/contactList'
},
// 新建联系人 form-data
newContactForm: {
method: 'post',
url: '/contact/new/form'
},
// 新建联系人 application/json
newContactJson: {
method: 'post',
url: '/contact/new/json'
},
// 编辑联系人
editContact: {
method: 'put',
url: '/contact/edit'
},
// 删除联系人
deleteContact: {
method: 'delete',
url: '/contact'
}
};
export default CONTACT_API;
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
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
import axios from 'axios';
import {Toast} from 'vant';
import service from './contactApi';
// service 循环遍历输出不同的请求方法
const instance = axios.create({
baseURL: 'http://localhost:9000/api',
timeout: 1000
});
// 包裹请求方法的容器
const HttpClient = {};
for (const key in service) {
if (service.hasOwnProperty(key)) {
const api = service[key];
// async:避免进入回调地狱
HttpClient[key] = async function (
params, // 请求参数 get/delete请求放到url中,put/post/patch放到请求体中
isFormData=false, // 标识是否是form-data请求
config={} // 配置参数,headers等
) {
let newParams = {};
if (params && isFormData) {
newParams = new FormData();
for (const key in params) {
if (params.hasOwnProperty(key)) {
newParams.append(key, params[key]);
}
}
} else {
newParams = params;
}
// 不同请求判断
let response = {}; // 请求的返回值
if (api.method === 'post' || api.method === 'patch' || api.method === 'put') {
try {
response = await instance[api.method](api.url, newParams, config);
} catch (error) {
response = error;
}
} else if (api.method === 'get' || api.method === 'delete') {
config.params = newParams;
try {
response = await instance[api.method](api.url, config);
} catch (error) {
response = error;
}
}
return response;
}
}
}
// 拦截器的添加
instance.interceptors.request.use(config => {
// 发送请求前做些事情
Toast.loading({
message: '加载中...',
forbidClick: true,
loadingType: 'spinner',
duration: 0 // 提示一直存在
});
return config;
}, () => {
Toast.clear(); // 清除加载中的提示
Toast.fail('请求失败,请稍后重试');
});
// 响应拦截器
instance.interceptors.response.use(res => {
Toast.clear();
return res.data;
}, () => {
Toast.clear(); // 清除加载中的提示
Toast.fail('请求失败,请稍后重试');
});
export default HttpClient;
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import HttpClient from './service/http'
Vue.config.productionTip = false
// 将HttpClient挂载到Vue实例上,这样就可以直接在页面中使用,不需要每次都引入了
Vue.prototype.$HttpClient = HttpClient
new Vue({
router,
render: h => h(App)
}).$mount('#app')
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
// 将HttpClient挂载到Vue实例上后,可以直接这样使用HttpClient
const res = await this.$HttpClient.editContact(info);
if (res.code === 200) {
this.showEdit = false;
Toast.success('编辑成功');
this.getList();
}
1
2
3
4
5
6
7
2
3
4
5
6
7