Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中
基本使用
创建实例
1
2
3
4
5
6
7
| import axios from 'axios'
// 创建实例
const service = axios.create({
baseURL: 'https://some-domain.com/api/', // 默认URL
timeout: 1000, // 超时时间
headers: { 'X-Custom-Header': 'foobar' } // 默认的请求头
})
|
这里推荐创建 实例, 这样可以有 差别化 配置项的请求客户端
修改配置
1
2
3
4
5
6
7
8
9
| import axios from 'axios'
const service = axios.create()
// >>>>>> 全局形式, 这样的修改将应用到整个站点的axios客户端内 <<<<<<
axios.defaults.baseURL = 'https://api.example.com'; // 所有AXIOS客户端对应请求的域名
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; // 所有类型的请求添加TOKEN
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; // 给POST类型请求单独增加头
// >>>>>> 实例形式, 如果考虑长期维护建议使用这种方式: <<<<<<
service.defaults.baseURL = 'https://api.example.com'; // 当前实例客户端对应的请求域名
|
状态码
默认 200
到 300
的响应状态码对应 Promise.resolve, 超出范围则 Promise.rejecte
可以传入回调方法来决定自己的调用状态, 若返回值为 true
, null
, undefined
均 resolve 否则 rejecte
1
2
3
4
| const service = axios.create({
validateStatus: status => status >= 200 && status < 300
})
// 或 validateStatus 加入到请求拦截器内
|
取消请求
1
2
3
4
5
6
7
| // 简单的取消例子
let cancel;
axios.get('/user/12345', {
cancelToken: new axios.CancelToken(func => cancel = func)
});
// 取消请求
cancel && cancel();
|
注意: 可以使用同一个 cancel token 取消多个请求
高级
数据处理
这里可以用于表单类型数据提交格式的转化
1
2
3
4
5
6
7
8
9
10
11
12
| const service = axios.create({
// `transformRequest` 允许在向服务器发送前,修改请求数据
// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data, headers) {
// 例如from-data格式化
// data = Qs.stringify(data, { arrayFormat: 'repeat' })
return data
}],
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [function (data) { return data }],
})
|
下载进度
1
2
3
4
5
6
| let percent, loaded, total;
axios.get("/demo/file.xlsx", data, {
onDownloadProgress(e) {
[loaded, total, percent] = [e.loaded, e.total, parseInt(100 * (e.loaded / e.total))] // 已下载/总大小/百分比
}
})
|
封装
响应封装
常见的错误处理及相应处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| import { Message, MessageBox } from 'element-ui' // 以 element-ui 为例
/* 每次响应后执行 */
service.interceptors.response.use(
response => {
// 根据 **validateStatus** 的默认配置, 只有200到300之间的状态码能执行这个方法, 固不判断
if (response.headers['content-type'] === "application/json") return response.data // 响应为JSON时, 只返回数据
return response // 其他类型响应返回原始对象
},
error => {
// 这里假设400错误的数据结构 {"message": "XXXX错误"}
if (error.response.status === 400) Message.error(error.response.data.message) // 立刻弹出错误信息
else if (error.response.status === 401) MessageBox.alert('您的登录信息已失效, 请重新登录!', '提示', { callback: () => logout() })
else Message.error(`服务器错误!\n${(error.response || {}).data || String(error)}`) // 立刻弹出错误信息
Promise.reject(error)
}
)
|
请求重试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| import axios from 'axios'
// 创建实例
const service = axios.create({ timeout: 5000 })
// 重试配置
const shouldRetry = (error) => true // 重试条件
axios.default.retry = 3 // 重试次数
axios.default.retryDelay = 2000 // 重试延时
axios.default.shouldRetry = shouldRetry
// 返回错误时拦截,并尝试重试
AxiosInst.interceptors.response.use(undefined, function (error) {
const config = (error.config || { __retryCount: 0 , shouldRetry}) // 默认值兼容
if (!config || !config.retry || config.__retryCount >= config.retry || config.shouldRetry(error)) return Promise.reject(error);
console.log(config.url + `自动重试第 ${config.__retryCount += 1} 次`) // 打印并增加重试次数
return new Promise(resolve => setTimeout(() => resolve(), config.retryDelay || 1)).then(() => axios(config))
})
|
文件
文件下载
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
| import axios from 'axios'
// 创建实例
const service = axios.create({ timeout: 5000 })
// 通用配置
axios.default.withCredentials = true // 跨域是否携带cookie
// 请求拦截器
service.interceptors.request.use(
/* 每次请求前执行, 准备的工作 */
config => {
config.headers = {
'access-token': '<携带你的TOKEN>', // 常见的携带token
}
return config
}, // 请求前配置修改
error => Promise.reject(error)
)
// 响应拦截器
service.interceptors.response.use(
/* 每次响应后执行 */
response => {
// 重试的实现逻辑
// TODO
// 文件下载的处理
if (response.request.responseType === 'blob' && response.status === 200) { // 下载文件
// 获取文件名
const filename = (response.headers['content-disposition'] || '')
.split('; ').reverse()[0].replace('filename=', '') || '未知文件格式'
// 下载方法
const link = document.createElement('a')
link.style.display = 'none'
link.href = window.URL.createObjectURL(new Blob([response.data]))
link.setAttribute('download', filename)
document.body.appendChild(link)
link.click()
setTimeout(() => document.body.removeChild(link), 1000) // 清除文件按钮
return response // 文件下载返回原本的响应对象
} else { // 非文件(二进制流)响应
if (response.status !== 200) { // 非成功的响应
/* 无权限则清除登录信息, 跳转登录页 */
if (response.status === 401) window.location.href = '/login'
/* >>>>>> 更多的状态码/响应头/内容来决定的逻辑 <<<<<< */
/* 弹窗警告, 并推出错误到调用层 */
return Promise.reject(new Error(response.data.message || 'Error'))
}
// 响应成功, 则直接返回数据, 无需关心其他属性
return response.data
}
},
error => Promise.reject(error)
)
export default service
|
查阅