/** * 封装 axios */ import axios from 'axios' import { ElMessage } from 'element-plus' import store from '@/store' import router from '@/router' import Config from '@/config' import autoJump from '@/lin/util/auto-jump' import ErrorCode from '@/config/error-code' import { getToken, saveAccessToken } from '@/lin/util/token' const config = { baseURL: Config.baseURL || '', timeout: 50 * 1000, // 请求超时时间设置 crossDomain: true, // withCredentials: true, // Check cross-site Access-Control // 定义可获得的http响应状态码 // return true、设置为null或者undefined,promise将resolved,否则将rejected validateStatus(status) { return status >= 200 && status < 510 }, } /** * 错误码是否是refresh相关 * @param { number } code 错误码 */ function refreshTokenException(code) { const codes = [10000, 10042, 10050, 10052, 10012] return codes.includes(code) } // 创建请求实例 const _axios = axios.create(config) _axios.interceptors.request.use( originConfig => { // 有 API 请求重新计时 autoJump(router) const reqConfig = { ...originConfig } // step1: 容错处理 if (!reqConfig.url) { console.error('request need url') } reqConfig.method = reqConfig.method.toLowerCase() // 大小写容错 // 参数容错 if (reqConfig.method === 'get') { if (!reqConfig.params) { reqConfig.params = reqConfig.data || {} } } else if (reqConfig.method === 'post') { if (!reqConfig.data) { reqConfig.data = reqConfig.params || {} } // 检测是否包含文件类型, 若包含则进行 formData 封装 let hasFile = false Object.keys(reqConfig.data).forEach(key => { if (typeof reqConfig.data[key] === 'object') { const item = reqConfig.data[key] if (item instanceof FileList || item instanceof File || item instanceof Blob) { hasFile = true } } }) // 检测到存在文件使用 FormData 提交数据 if (hasFile) { const formData = new FormData() Object.keys(reqConfig.data).forEach(key => { formData.append(key, reqConfig.data[key]) }) reqConfig.data = formData } } // step2: permission 处理 if (reqConfig.url === 'cms/user/refresh') { const refreshToken = getToken('refresh_token') if (refreshToken) { reqConfig.headers.Authorization = refreshToken } } else { const accessToken = getToken('access_token') if (accessToken) { reqConfig.headers.Authorization = accessToken } } return reqConfig }, error => Promise.reject(error), ) // Add a response interceptor _axios.interceptors.response.use( async res => { // 如果是文件下载响应,直接处理文件 if (res.config.responseType === 'blob') { return res; // 直接返回文件流,交给调用方法处理 } if (res.status.toString().charAt(0) === '2') { return res.data } const { code, message } = res.data return new Promise(async (resolve, reject) => { let tipMessage = '' const { url } = res.config // refresh_token 异常,直接登出 if (refreshTokenException(code)) { setTimeout(() => { store.dispatch('loginOut') const { origin } = window.location window.location.href = origin }, 1500) return resolve(null) } // assessToken相关,刷新令牌 if (code === 10041 || code === 10051) { const cache = {} if (cache.url !== url) { cache.url = url const refreshResult = await _axios('cms/user/refresh') saveAccessToken(refreshResult.access_token) // 将上次失败请求重发 const result = await _axios(res.config) return resolve(result) } } // 弹出信息提示的第一种情况:直接提示后端返回的异常信息(框架默认为此配置); // 特殊情况:如果本次请求添加了 handleError: true,用户自行通过 try catch 处理,框架不做额外处理 if (res.config.handleError) { return reject(res) } // 弹出信息提示的第二种情况:采用前端自己定义的一套异常提示信息(需自行在配置项开启); // 特殊情况:如果本次请求添加了 showBackend: true, 弹出后端返回错误信息。 if (Config.useFrontEndErrorMsg && !res.config.showBackend) { // 弹出前端自定义错误信息 const errorArr = Object.entries(ErrorCode).filter(v => v[0] === code.toString()) // 匹配到前端自定义的错误码 if (errorArr.length > 0 && errorArr[0][1] !== '') { ;[[, tipMessage]] = errorArr } else { tipMessage = ErrorCode['777'] } } if (typeof message === 'string') { tipMessage = message } if (Object.prototype.toString.call(message) === '[object Object]') { ;[tipMessage] = Object.values(message).flat() } if (Object.prototype.toString.call(message) === '[object Array]') { ;[tipMessage] = message } ElMessage.error(tipMessage) reject(res) }) }, error => { if (!error.response) { ElMessage.error('请检查 API 是否异常') console.log('error', error) } // 判断请求超时 if (error.code === 'ECONNABORTED' && error.message.indexOf('timeout') !== -1) { ElMessage.warning('请求超时') } return Promise.reject(error) }, ) // 导出常用函数 /** * @param {string} url * @param {object} data * @param {object} params */ export function post(url, data = {}, params = {}) { return _axios({ method: 'post', url, data, params, }) } /** * @param {string} url * @param {object} params */ export function get(url, params = {}) { return _axios({ method: 'get', url, params, }) } /** * @param {string} url * @param {object} data * @param {object} params */ export function put(url, data = {}, params = {}) { return _axios({ method: 'put', url, params, data, }) } /** * @param {string} url * @param {object} params */ export function _delete(url, params = {}) { return _axios({ method: 'delete', url, params, }) } export default _axios