Appearance
Axios 说明文档
概述
axios 全局拦截器,在接口发出前及接收时进行统一管理
配置
baseURL 域名设置
一般项目会分为三种环境(NODE_ENV):开发环境、测试环境、生产环境,每一种环境下的域名都不一样,因此需要进行统一设置
若为开发环境,直接使用默认的 baseURL,但需要增加 proxy 前缀;其他环境不需要使用 proxy,直接设置对应域名即可
const { NODE_ENV, VUE_APP_PROXY_PREFIX, VUE_APP_BASE_URL } = process.env
const baseURL = NODE_ENV === 'development' ? VUE_APP_PROXY_PREFIX : VUE_APP_BASE_URL
const service = axios.create({
baseURL,
})
发送时拦截器
一般用于配置统一的 withCredentials
凭证、timeout
超时、auth
请求头等
用户登录 token 校验,一般会存储在请求头的auth
字段上,参考如下
import { getToken } from '@/utils/auth'
service.interceptors.request.use(config => {
config.headers = getToken()
return config
})
接收时拦截器
初步处理接口返回的数据,可以针对某些特定的状态码执行一些特定的操作,需要视项目(看后端)而定,其他状态码由各接口函数内部处理,目前内部使用的标准是在原生的网络状态码的基础上,再自定义一套内部前后端团队使用的状态码标准(前端请求到达服务端则统一返回200状态码,在响应数据中指定自定义状态码code、响应信息message、响应结果data),参数格式如下:
// 完整的axios响应报文,大部分情况下,我们只需要拿到data中的数据,所以可以在axios的响应拦截器中截取data下发给下级程序
{
"data": {
"code": 200,
"message": "请求成功",
"data": {
"key": "a23f3ed9-37af-4068-94c4-c3c34e50f531",
"image": "data:image/png;base64,iVBO……"
},
"timestamp": 1631007565893
},
"status": 200,
"statusText": "OK",
"headers": {
"connection": "close",
"content-type": "application/json;charset=UTF-8",
"date": "Tue, 07 Sep 2021 09:39:25 GMT",
"transfer-encoding": "chunked",
"x-powered-by": "Express"
},
"config": {
"url": "/login/captcha",
"method": "get",
"headers": {
"Accept": "application/json, text/plain, */*",
"Authorization": ""
},
"baseURL": "/@API",
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"params": {
"_t": 1631007566853
}
},
"request": {}
}
现在需要axios响应拦截器做的,就是判断原生状态码是否200,是200则截取响应返回的data给下级程序,如果不是的话,那就直接抛出错误,如下:
if (response.status === 200) {
return response.data
} else {
throw response.data
}
再深一层次的封装就是再给自定义状态码做一层判断,例如code为10200表示请求正常,直接返回Promise.resolve(response.data)
,code为10040时,代表登录过期,可弹窗提示用户"登录过期,请重新登录",再导向登录界面;
注意事项
get请求被缓存
解决 IE 浏览器下 get 请求参数不变时,请求走了缓存(302),而没有走到服务端,只需要统一在发送拦截器中判断 get 请求并拼接上时间戳参数,参考如下:
service.interceptors.request.use(config => {
if (config.method === 'get') {
if (!config.params) config.params = {}
config.params._t = Date.now()
}
return config
})
get无法发送数组参数
解决 get 请求无法发送数组参数,需要在axios实例化时paramsSerializer
或配置发送拦截器时判断 get 请求,并设置 paramsSerializer
(参数序列化)格式,要搭配插件qs
,请提前安装好,参考如下:
service.interceptors.request.use(config => {
if (config.method === 'get') {
config.paramsSerializer = function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
}
return config
})
qs
的对象序列化参考:
qs.stringify({ids: [1, 2, 3]}, { indices: false })
//形式: ids=1&ids=2&id=3
qs.stringify({ids: [1, 2, 3]}, {arrayFormat: ‘indices‘})
//形式: ids[0]=1&aids1]=2&ids[2]=3
qs.stringify({ids: [1, 2, 3]}, {arrayFormat: ‘brackets‘})
//形式:ids[]=1&ids[]=2&ids[]=3
qs.stringify({ids: [1, 2, 3]}, {arrayFormat: ‘repeat‘})
//形式: ids=1&ids=2&id=3
除了给get请求设置参数序列化,如后端接受的post请求内容格式为x-www-form-urlencoded
,也可以做统一的参数序列化处理
get请求无法发送请求体参数
axios的get请求本就不能发送请求体参数,get请求发送请求体参数不符合规范,官方文档中有进行描述,请避免使用get请求发送请求体参数的形式;
下载二进制文件
下载二进制流文件时,请在axios接口中添加上参数responseType
,参考如下:
axios.get('/download', { responseType: 'arraybuffer' })
MDN中对responseType的相关描述;
设置接口超时
除了axios实例化的时候设置全局的接口超时之外,在接口请求的配置中也可以单独设置请求超时时间,参考如下:
// 默认超时是6000ms,即60s
axios.get('/download', { timeout: 2 * 60 * 1000 })
注意的是,nginx之类的代理服务器也存在超时时间,也需要设置读取超时时间;