全局错误处理
import { ElMessage } from 'element-plus';
const errorType = {
vue: '捕获组件错误',
error: '捕获javascrpit错误',
unhandledrejection: '捕获javascrpit异步错误',
};
const errorHandler = (type, error) => {
if (!error) return;
console.error(`%c ${errorType[type]}`, 'background-color: red;');
console.error(error);
ElMessage.error((error && (error.msg || error.message)) || '未知错误');
};
export const vueErrorHandler = {
install: Vue => {
Vue.config.errorHandler = error => {
errorHandler('vue', error);
};
},
};
window.addEventListener('error', function (event) {
errorHandler('error', event.error);
});
window.addEventListener('unhandledrejection', function (event) {
errorHandler('unhandledrejection', event.reason);
});
全局axios接口返回错误统一处理
import axios from 'axios';
import store from '@/store/index';
import router from '../router/index';
import { AXIOS_BASE_URL } from '@/constant/constant.js';
export const request = axios.create({
baseURL: AXIOS_BASE_URL,
timeout: 1000 * 10 * 3,
withCredentials: false,
});
request.interceptors.request.use(
config => {
const user = store.state.app.user;
if (user && user.F_token) {
config.headers['F_token'] = user.F_token;
}
return config;
},
error => {
return Promise.reject(error);
},
);
request.interceptors.response.use(
response => {
if (response.config.responseType === 'blob') {
return processResponse(response);
}
if (!response.data.code && !response.data.result) {
const data = {};
data.code = 200;
data.msg = null;
if (
Array.isArray(response.data) ||
response.data == null ||
typeof response.data !== 'object' ||
!response.data.data
) {
data.data = response.data;
} else {
Object.assign(data, response.data);
}
response.data = data;
}
return processResponse(response);
},
error => {
if (error.response && error.response.status === 401) {
router.push('/login');
return;
}
return Promise.reject(error);
},
);
const default_retryTimes = 0;
const default_retryDelay = 1000 * 3;
const MAX_COUNT = 5;
const requestQueue = [];
let activeCount = 0;
function processQueue() {
if (activeCount < MAX_COUNT && requestQueue.length) {
const { config, retryTimes, retryDelay, resolve, reject } = requestQueue.shift();
activeCount++;
request(config)
.then(response => {
resolve(response);
})
.catch(error => {
if (retryTimes === 0) {
reject(error);
} else {
setTimeout(() => {
requestQueue.push({
config,
retryTimes: retryTimes - 1,
retryDelay,
resolve,
reject,
});
}, retryDelay);
}
})
.finally(() => {
activeCount--;
processQueue();
});
}
}
function requestHandler(config, retryTimes = default_retryTimes, retryDelay = default_retryDelay) {
return new Promise((resolve, reject) => {
requestQueue.push({ config, retryTimes, retryDelay, resolve, reject });
processQueue();
});
}
function processResponse(response) {
if (response.data.code !== 200 && !['success', 'warning'].includes(response.data.result)) {
if (response.config.responseType === 'blob') {
return response;
}
if (response.data && typeof response.data !== 'object') {
Promise.reject({ msg: '接口返回JSON数据格式错误' });
}
if (response.data.code === 401) {
router.push('/login');
return;
}
if (!navigator.onLine) {
Promise.reject({ msg: '当前网络不可用,需检查你的网络设置' });
}
return Promise.reject(response.data);
}
return response.data;
}
request.get = (url, options) => {
const opt = {
...options,
url,
method: 'get',
};
return requestHandler(opt);
};
request.post = (url, data, options) => {
const opt = {
...options,
url,
data,
method: 'post',
};
return requestHandler(opt);
};
request.delete = (url, id, options) => {
const opt = {
...options,
url: url + '/' + id,
method: 'delete',
};
return requestHandler(opt);
};
request.put = (url, data, options) => {
const opt = {
...options,
url,
data,
method: 'put',
};
return requestHandler(opt);
};
request.patch = (url, data, options) => {
const opt = {
...options,
url,
data,
method: 'patch',
};
return requestHandler(opt);
};
request.downFile = (url, option, fileName) => {
const options = {
...option,
responseType: 'blob',
};
return request.get(url, options).then(res => {
const disposition = res.headers['content-disposition'];
if (!fileName) {
const match = disposition.match(/filename=([^;]+)/i);
if (match && match[1]) {
fileName = match[1].trim().replace(/^"|"$/g, '');
}
}
const blob = new Blob([res.data]);
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
if (fileName) {
a.setAttribute('download', fileName);
} else {
a.setAttribute('download', '');
}
a.click();
});
};
import axios from 'axios';
export interface CustomAxiosResponse {
code: number;
data?: any;
msg?: string;
message?: string;
}
declare module 'axios' {
export interface AxiosRequestConfig {
loading?: object | boolean;
}
export interface AxiosInstance {
get(url: string, config?: AxiosRequestConfig): Promise<CustomAxiosResponse>;
post(url: string, data: any, config?: AxiosRequestConfig): Promise<CustomAxiosResponse>;
downFile(url: string, config?: AxiosRequestConfig, fileName: string): void;
}
}
全局loading处理
import { ElLoading } from 'element-plus';
import { isObject } from './util';
class Loading {
private loadingNum: number;
private load;
private options: object = {
fullscreen: true,
};
constructor() {
this.loadingNum = 0;
}
start(options: object | boolean) {
if (this.loadingNum == 0) {
if (isObject(options)) {
this.options = options as object;
}
this.load = ElLoading.service(this.options);
}
this.loadingNum++;
}
end() {
this.loadingNum--;
if (this.loadingNum <= 0) {
this.load.close();
}
}
}
export const load = new Loading();