/** * 自定义 request 网络请求工具,基于axios * @author LiQingSong */ import axios, { AxiosPromise, AxiosRequestConfig, AxiosResponse } from 'axios'; import router from '@/router/routes'; import settings from '@/config/settings'; import { getToken } from '@/util/auth'; import { ElMessage } from 'element-plus'; import website from '@/config/website' import { Base64 } from 'js-base64'; import NProgress from 'nprogress'; import { serialize } from '@/util/util'; import { useStore } from "vuex"; import store from '@/config/store' export interface ResponseData { code: number; data?: any; msg?: string; token?: string; error_code?: string; error_description?: string; } const customCodeMessage: { [key: number]: string } = { 10002: '当前用户登入信息已失效,请重新登入再操作', // 未登陆 }; const serverCodeMessage: { [key: number]: string } = { 200: '服务器成功返回请求的数据', 400: 'Bad Request', 401: 'Unauthorized', 403: 'Forbidden', 404: 'Not Found', 500: '服务器发生错误,请检查服务器(Internal Server Error)', 502: '网关错误(Bad Gateway)', 503: '服务不可用,服务器暂时过载或维护(Service Unavailable)', 504: '网关超时(Gateway Timeout)', }; /** * 异常处理程序 */ const errorHandler = (error: any) => { const { response, message } = error; if (message === 'CustomError') { // 自定义错误 const { config, data } = response; const { url, baseURL } = config; const { code, msg } = data; const reqUrl = url.split("?")[0].replace(baseURL, ''); const noVerifyBool = settings.ajaxResponseNoVerifyUrl.includes(reqUrl); if (!noVerifyBool) { ElMessage({ message: customCodeMessage[code] || msg || 'Error', type: 'error' }); if (code === 10002) { router.replace('/user/login'); } } } else if (message === 'CancelToken') { // 取消请求 Token // eslint-disable-next-line no-console console.log(message); } else if (response && response.status) { const errorText = response.data.msg || serverCodeMessage[response.status] || response.statusText; ElMessage({ message: errorText, type: 'error' }); } else if (!response) { // ElMessage({ // message: '您的网络发生异常,无法连接服务器', // type: 'error' // }); } return Promise.reject(error); } /** * 配置request请求时的默认参数 */ const request = axios.create({ baseURL: '/', //process.env.VUE_APP_APIHOST, // url = api url + request url withCredentials: true, // 当跨域请求时发送cookie timeout: 10000 // 请求超时时间,5000(单位毫秒) / 0 不做限制 }); //返回其他状态码 request.defaults.validateStatus = function (status) { return status >= 200 && status <= 500; }; // NProgress 配置 NProgress.configure({ showSpinner: false }); /** * 请求前 * 请求拦截器 */ request.interceptors.request.use( async (config: AxiosRequestConfig & { cType?: boolean }) => { //开启 progress bar NProgress.start(); const meta = ((config as any).meta || {}); const isToken = meta.isToken === false; config.headers['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`; //让每个请求携带token if (getToken() && !isToken) { config.headers[website.tokenHeader] = 'bearer ' + getToken() } //headers中配置text请求 if ((config as any).text === true) { config.headers["Content-Type"] = "text/plain"; } //headers中配置serialize为true开启序列化 if (config.method === 'post' && meta.isSerialize === true) { config.data = serialize(config.data); } // 如果设置了cType 说明是自定义 添加 Content-Type类型 为自定义post 做铺垫 // if (config['cType']) { // config.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'; // } // 自定义添加token header // const headerToken = await getToken(); // if (headerToken) { // config.headers[settings.ajaxHeadersTokenKey] = headerToken; // } return config; }, /* error=> {} */ // 已在 export default catch ); /** * 请求后 * 响应拦截器 */ request.interceptors.response.use( async (response: AxiosResponse) => { const res: ResponseData = response.data; //关闭 progress bar NProgress.done(); //获取状态码 const status = res.error_code || res.code || response.status; const statusWhiteList = website.statusWhiteList || []; const message = res.error_description || res.msg || res.error_description || '未知错误'; //如果在白名单里则自行catch逻辑处理 if (statusWhiteList.includes(status as never)) return Promise.reject(response); //如果是401则跳转到登录页面 if (status === 401) { store.dispatch('FedLogOut').then(() => router.push({ path: '/login' })); router.push({ path: '/login' }) } // 如果请求为非200否者默认统一处理 if (status !== 200) { ElMessage({ message: message, type: 'error' }); return Promise.reject(new Error(message)) } // const url = (response as any).config.url // const res: ResponseData = response.data; // const { code, token } = res; // const urls = ['/api/coder-auth/oauth/token','/api/coder-auth/oauth/captcha'] // const resUrl = url.split('?')[0]; // if(urls.indexOf(resUrl) > -1){ // if (code && code !== 200) { // const message = res.data.msg || res.data.error_description || '未知错误'; // ElMessage({ // message: message, // type: 'error' // }); // return Promise.reject(new Error(message)) // } // return response // } // // 自定义状态码验证 // if (code !== 0 && code !== 200) { // const errorDescription = (res as any).error_description // const message = errorDescription || res.data.msg || res.data.error_description || '未知错误'; // ElMessage({ // message: message, // type: 'error' // }); // return Promise.reject(new Error(message)) // // return Promise.reject({ // // response, // // message: 'CustomError', // // }); // } // // 重置刷新token // if (token) { // await setToken(token); // } return response; }, /* error => {} */ // 已在 export default catch ); /** * ajax 导出 * * Method: get * Request Headers * 无 - Content-Type * Query String Parameters * name: name * age: age * * Method: post * Request Headers * Content-Type:application/json;charset=UTF-8 * Request Payload * { name: name, age: age } * Custom config parameters * { cType: true } Mandatory Settings Content-Type:application/json;charset=UTF-8 * ...... */ export default function (config: AxiosRequestConfig): AxiosPromise { return request(config).then((response: AxiosResponse) => response.data).catch(error => errorHandler(error)); }