• 如果有mockjs操作 会影响 axios 的默认配置

  • 会对发出请求的 url 进行如下转码操作 lib\helpers\buildURL.js

encodeURIComponent(val).
    replace(/%3A/gi, ':').
    replace(/%24/g, '$').
    replace(/%2C/gi, ',').
    replace(/%20/g, '+').
    replace(/%5B/gi, '[').
    replace(/%5D/gi, ']');

上传 FormData数据

axios 可以自动判断上传的数据是否是formdata,从而修改 content-type, 只需要设置 request config 的 data { data: FormData }

终止请求

取消一个已经发出的请求

const controller = new AbortController(); // 目前看源码是 axios 重写了AbortController方法【20220930】

axios.get('/foo/bar', {
   signal: controller.signal
}).then(function(response) {
   // 
});
// 取消成功后 如果用了 response 拦截 需要在 error 回调中处理
controller.abort()

简单封装

import { v1 as uuId } from 'uuid'
import axios from 'axios'
import { Message } from 'element-ui'
import { getDomain } from '@/utils/common'

/**
 * @des get 方式,参数放 params
 * @des post put 等方式,参数放 data
 * @des post patch 等方式有 params data 参数,当只传 params 时,会转换赋值到data上 与axios需要的参数一致
 * @des 这里默认返回的数据结构 { code: '自定义状态码  当前项目 1 表示成功', data: '结果', msg: '结果描述' }
 */
const httpService = axios.create({
    withCredentials: true, // 跨域携带cookie,设置为true,服务器也需要设置,一般不推荐如此使用
    timeout: 0,
    headers: { Authorization: 'hewitt' }
})

httpService.interceptors.request.use((cfg) => {
    const { url, method, params, data, commonPre = '/api' } = cfg

    /* 重置或配置 headers 的值 */
    cfg.headers.uuid = uuId().replace(/-/g, '')
    cfg.headers.token = '' || '' // 注意传token时不要出现 undefined 都会被识别成字符串带入校验,如果没有就传空或者不设备这个头

    /**
     * @des 处理url中带参数(例:/xx/:id/xx/ -> /xx/123/xx/)  这里的参数要带在 params 里,(不推荐这种写法240220)
     */
    if (/:/.test(url)) {
        const urlParam = /\/:([^/]+)(?:\/|$)/.exec(url)[1]
        cfg.url = url.replace(`:${urlParam}`, params[urlParam])
        delete cfg.params[urlParam]
    }

    /**
     * @des 统一处理 formData 传参
     * 定义接口时设置 formData: true; 配置 data 字段
     */
    if (formData) {
        const formData = new FormData()
        Object.keys(data).forEach(k => {
            formData.append(k, data[k])
        })
        cfg.data = formData
    }

    /**
     * @des 如果没有配置反向代理,可直接加地址
     */
    // console.log('NODE_ENV', process.env.NODE_ENV)
    /* 公共前缀默认 api */
    cfg.baseURL = getDomain()

    return cfg
}, (error) => {
    /* 这里基本不会进入,一般在 response 的捕获中处理 */
    return Promise.reject(error)
})

httpService.interceptors.response.use((res) => {
    const { config, data } = res

    /**
     * 注意 showSuccessMsg 参数实在 api文件里面的方法中传递的,是和url同一级
     * code === 'xxx 根据不同的后端数据结构来定义'
     * 一般不统一处理成功,只处理报错信息显示
     **/
    if (config.showSuccessMsg && data.code === 1) {
        Message({
            message: data.msg,
            type: 'success',
            duration: 2000
        })
    }

    /* 
        excludeCode 默认 false,表示返回的数据格式是符合统一标准的;
        当设置为true时,表示不对code检测判断错误,一般用于返回数据格式不规范(没有返回code)时使用  
    */
    if (data.code !== 1 && !config.excludeCode) {
        /* 这里的错误,只做提示信息的统一处理,因为每一个地方的错误处理业务不同 */
        Message({
            message: data.msg,
            type: 'error',
            duration: 2000
        })

        return Promise.reject(res.data)
    }

    // 所有操作成功,然后返回  这里成功,code也不做返回  只返回成功的数据
    return res.data.data
}, (error) => {
    /**
     * 接口报错 404等 会进入
     * request 中抛出的错误、reject 会进入  这里的 error 对象就是,自己抛出的错误对象,自己封装的 error 对象 错误信息字段务必用 message 与 axios 封装的一致
     * 这里如果是axios 捕获的超时或服务器报错 会返回一个 封装好的 error  对象, error.message
     * 这里可以用  error.toJSON()  打印 error中的一些信息 比如 error.code  
     * 
     */
    if (error.code === 404) {
        Message({ message: '接口未找到', type: 'error', duration: 2000 })
    } else {
        Message({ message: error.message, type: 'error', duration: 2000 })
    }

    /* 这里的返回 有需要 可以在业务代码的 catch 中获取 再进行特殊的异常处理 */
    return Promise.reject(error)
})

/* 公共前缀 */
export const httpCommonManage = (params) => {
    params.commonPre = '/some'
    return httpService(params)
}

export default httpService
Last Updated:
Contributors: Warren, Warren