动手封装一个Axios库
前言
考虑到日常业务需求以及数据通信的重要性,决定动手在Axios
的基础之上封装一个通用的库。
需求分析及实现
- 统一捕获接口的报错信息
- 对报错信息进行友好提示
- 报错后的重定向问题
- 基础的鉴权功能
- 表单序列化
相关用法以及封装
// 服务层,import 会 优先查找对应名字的文件,如未查找到,则会查找该对应名字的文件夹下的index.js文件
import AxiosInstance from './request'
Vue.use(AxiosInstance)
1
2
3
2
3
封装Axios库
// request/index.js
import Axios from 'axios'
import qs from 'qs'
import { Message } from 'element-ui'
import router from '../../router'
const AxiosInstance = Axios.create({
baseURL: '', // 用来设置公共url
timeout: 3000,// 请求时间
response: 'json',
withCredentials: true, // 是否允许携带 Cookie
headers: {
'Content-Type': 'application/json;charset=utf8'
}
})
// 请求状态拦截器
AxiosInstance.interceptors.request.use(config => {
// 请求数据前进行相关操作
if (config.method === 'POST') {
// 序列化数据,如后端可接受json数据格式,可省略这一步
config.data = qs.stringify(config.data)
}
// 如果需要做鉴权 token ,就添加头部token
// token 最好不放入 vuex中,当浏览器刷新后,token就会被重置
// 一般通过将数据存入浏览器cookie,localStorage中
if (localStorage.token) {
config.headers.Authorization = localStorage.token
}
return config
}, error => {
// error 回调信息,规定错误信息的返回形式
// 有关Message使用方法,建议查看element官网
Message({
showClose: true,
message: error && error.data.error.message,
type: 'error'
})
return Promise.reject(error.data.error.message)
})
// 响应状态拦截器
AxiosInstance.interceptors.response.use(res => {
if (res.data && !res.data.succes) {
Message({
showClose: true,
message: res.data.error.message.message
? res.data.error.message.message
: res.data.error.message,
type: 'error'
})
return Promise.reject(res.data.error.message)
}
return res
}, error => {
// 用户登录时会获取基本信息,如用户名,token,过期时间等
// token 一般存入storage或cookie中
// 这里的 token 名字随意
if (!localStorage.getItem('login_info')) {
// 判断localstorage中是否存在该 token
// 若不存在,回退到登录页面
router.push({
path: '/login'
})
} else {
// 如token信息存在,继续判断服务器过期时间是否小于当前日期
// 如已经过期重新登录
const expires_time = JSON.parse(localStorage.getItem('login_info')).expires_time * 1000
const current_time = Date.now()
if (current_time > expires_time) {
Message({
showClose: true,
message: '登陆状态信息过期,请重新登录',
type: 'error'
})
router.push({
path: '/login'
})
} else {
// 下面是一些状态码错误处理
switch (error.response.status) {
case 403:
router.push({
path: '/error/page403'
})
break
case 404:
router.push({
path: '/error/page404'
})
break
case 500:
router.push({
path: '/error/page500'
})
break
default:
break
}
}
const error_info = error.data.error
? error.data.error.message
: error.data
return Promise.reject(error_info)
}
})
export default {
install: function(Vue,options) {
Object.defineProperty(Vue, $axios, AxiosInstance)
}
}
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
调整路由
配置路由表中相关信息,请忽视路由内容
// router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import { Message } from 'element-ui'
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
]
})
// 路由拦截
// 通过给路由设置meta信息判断是否需要鉴权
// 类似于登录,注册等页面是不需要鉴权就可以直接访问的
// meta信息中添加一个 requireLogin 字段用于判断鉴权
router.beforeEach((to, from, next) => {
if (to.matched.some(res => res.meta.requireLogin)) {
// 如果需要登录权限
if (localStorage.getItem('login_info')) {
//判断是否已经登录
const expires_time =
JSON.parse(localStorage.getItem('login_info')).expires_time * 1000
const current_time = Date.now()
if(current_time < expires_time) {
next()
} else {
Message({
showClose: true,
message: '登录状态信息过期,请重新登录',
type:'error'
})
next({
path:'/login'
})
}
} else {
// 不需要登录权限 直接操作即可
next()
}
}
})
export default router
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
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
axios中可配置的选项,具体信息可查看npm-axios
export default {
// 请求地址
url: "/user",
// 请求类型
method: "get",
// 请根路径
baseURL: "http://www.mt.com/api",
// 请求前的数据处理
transformRequest: [function(data) {}],
// 请求后的数据处理
transformResponse: [function(data) {}],
// 自定义的请求头
headers: { "x-Requested-With": "XMLHttpRequest" },
// URL查询对象
params: { id: 12 },
// 查询对象序列化函数
paramsSerializer: function(params) {},
// request body
data: { key: "aa" },
// 超时设置s
timeout: 1000,
// 跨域是否带Token
withCredentials: false,
// 自定义请求处理
adapter: function(resolve, reject, config) {},
// 身份验证信息
auth: { uname: "", pwd: "12" },
// 响应的数据格式 json / blob /document /arraybuffer / text / stream
responseType: "json",
// xsrf 设置
xsrfCookieName: "XSRF-TOKEN",
xsrfHeaderName: "X-XSRF-TOKEN",
// 下传和下载进度回调
onUploadProgress: function(progressEvent) {
Math.round(progressEvent.loaded * 100 / progressEvent.total);
},
onDownloadProgress: function(progressEvent) {},
// 最多转发数,用于node.js
maxRedirects: 5,
// 最大响应数据大小
maxContentLength: 2000,
// 自定义错误状态码范围
validateStatus: function(status) {
return status >= 200 && status < 300;
},
// 用于node.js
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// 用于设置跨域请求代理
proxy: {
host: "127.0.0.1",
port: 8080,
auth: {
username: "aa",
password: "2123"
}
},
// 用于取消请求
cancelToken: new CancelToken(function(cancel) {})
};
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
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
总结
通过简单的封装Axios库,实现了上述所列基本功能,实际情况可按照公司要求另行配置。
比如:鉴权系统,token 遵循 JWT 规范,以及对Node中间层数据请求的拦截封装等。