import axios from "axios"; import qs from "qs"; // 引入axios时同时引入qs即可。 import { Message, MessageBox } from "element-ui"; import store from "../store"; import { getToken } from "@/utils/auth"; // 正在进行中的请求列表 const reqList = []; /** * 阻止重复请求 * @param {array} reqList - 请求缓存列表 * @param {string} url - 当前请求地址 * @param {function} cancel - 请求中断函数 * @param {string} errorMessage - 请求中断时需要显示的错误信息 */ const stopRepeatRequest = function(reqList, url, cancel, errorMessage) { const errorMsg = errorMessage || ""; for (let i = 0; i < reqList.length; i++) { if (reqList[i] === url) { cancel(errorMsg); return; } } reqList.push(url); }; /** * 允许某个请求可以继续进行 * @param {array} reqList 全部请求列表 * @param {string} url 请求地址 */ const allowRequest = function(reqList, url) { for (let i = 0; i < reqList.length; i++) { if (reqList[i] === url) { reqList.splice(i, 1); break; } } console.log(reqList); }; axios.interceptors.request.use( config => { if (config.method === "post") { config.data = qs.stringify(config.data); } return config; }, error => { return Promise.reject(error); } ); // const baseURL = process.env.BASE_API // 创建axios实例 const service = axios.create({ // baseURL: baseURL, // api的base_url axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'; timeout: 30000, // 请求超时时间 headers: { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" }, // `transformRequest` 允许在向服务器发送前,修改请求数据 // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法 // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream // 解决axios默认发送数据时,数据格式是Request Payload的问题 transformRequest: [ function(data) { // 对 data 进行任意转换处理 return qs.stringify(data); } ], // `paramsSerializer` 是一个负责 `params` 序列化的函数 // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/) // return qs.stringify({ids: [1, 2, 3]}, {indices: false}) // 形式:ids=1&ids=2&id=3 // return qs.stringify({ids: [1, 2, 3]}, {arrayFormat: 'indices'}) // 形式:ids[0]=1&ids[1]=2&ids[2]=3 // return qs.stringify({ids: [1, 2, 3]}, {arrayFormat: 'brackets'}) // 形式:ids[]=1&ids[]=2&ids[]=3 // return qs.stringify({ids: [1, 2, 3]}, {arrayFormat: 'repeat'}) // 形式: ids=1&ids=2&id=3 paramsSerializer: function(params) { return qs.stringify(params, { arrayFormat: "indices" }); // 形式:ids=1&ids=2&id=3 } }); // request拦截器 service.interceptors.request.use( config => { if (store.getters.token) { // config.headers["Authorization"] = getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改 Bearer } config.url = config.url + "?token=" + getToken(); let cancel; if (config.method === "post") { // 设置cancelToken对象 config.cancelToken = new axios.CancelToken(function(c) { cancel = c; }); // 阻止重复请求。当上个请求未完成时,相同的请求不会进行 stopRepeatRequest( reqList, config.url, cancel, `${config.url} 请求被中断` ); // stopRepeatRequest(reqList, config.url, cancel, `请求被中断`) } else { } return config; }, error => { // Do something with request error Promise.reject(error); } ); // respone拦截器 service.interceptors.response.use( response => { /** * state为非"success"时抛错 */ // 增加延迟,相同请求不得在短时间内重复发送 if (response.config.method === "post") { setTimeout(() => { const replaceList = response.config.url.split("/"); const newUrl = replaceList[replaceList.length - 2] + "/" + replaceList[replaceList.length - 1]; allowRequest(reqList, newUrl); }, 1000); } const res = response.data; if (res.state && res.state.toLowerCase() !== "success") { Message({ message: res.message, type: "error", duration: 5 * 1000 }); // 50008:非法的token; 50012:其他客户端登录了; "notoken":Token 过期了 if ( res.state.toLowerCase() === 50008 || res.state.toLowerCase() === 50012 || res.state.toLowerCase() === "notoken" ) { MessageBox.confirm( "你已被登出,可以取消继续留在该页面,或者重新登录", "确定登出", { confirmButtonText: "重新登录", cancelButtonText: "取消", type: "warning" } ).then(() => { store.dispatch("FedLogOut").then(() => { location.reload(); // 为了重新实例化vue-router对象 避免bug }); }); } return Promise.reject("error"); } else { if (response.config.responseType === "blob") { return response; } return response.data; } }, error => { if (error && !error.message && error.response.config.method === "post") { setTimeout(() => { const replaceList = error.response.config.url.split("/"); const newUrl = replaceList[replaceList.length - 2] + "/" + replaceList[replaceList.length - 1]; allowRequest(reqList, newUrl); }, 500); } console.log("err:" + error); // for debug if (error && error.response) { switch ( error.response.status // 跨域存在获取不到状态码的情况 ) { case 400: error.message = `请求错误(400):${error.response.config.url}`; break; case 401: error.message = `未授权,请登录(401):${error.response.config.url}`; store.dispatch("FedLogOut").then(() => { location.reload(); // 为了重新实例化vue-router对象 避免bug }); break; case 403: error.message = `拒绝访问(403):${error.response.config.url}`; break; case 404: error.message = `请求地址出错(404): ${error.response.config.url}`; break; case 408: error.message = `请求超时(408):${error.response.config.url}`; break; case 500: error.message = `服务器内部错误(500):${error.response.config.url}`; break; case 501: error.message = `服务未实现(501):${error.response.config.url}`; break; case 502: error.message = `网关错误(502):${error.response.config.url}`; break; case 503: error.message = `服务不可用(503):${error.response.config.url}`; break; case 504: error.message = `网关超时(504):${error.response.config.url}`; break; case 505: error.message = `HTTP版本不受支持(505):${error.response.config.url}`; break; default: error.message = `连接错误:${error.response.status}`; break; } } else if (error.message.indexOf("请求被中断") !== -1) { error.message = "请勿重复请求!"; } else { error.message = "网络出现问题,请稍后重试!"; } Message({ message: error.message, type: "error", duration: 5 * 1000 }); return Promise.reject(error); } ); export default service;