Skip to content
On this page

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之类的代理服务器也存在超时时间,也需要设置读取超时时间;

参考地址

axios 文档 🚀