|
@@ -1,85 +1,85 @@
|
|
|
-import axios, { AxiosInstance, AxiosResponse, AxiosError, AxiosRequestConfig } from 'axios';
|
|
|
-import { ElMessage, ElMessageBox, ElLoading, LoadingOptionsResolved } from 'element-plus';
|
|
|
+import axios, {AxiosInstance, AxiosResponse, AxiosError, AxiosRequestConfig} from 'axios';
|
|
|
+import {ElMessage, ElMessageBox, ElLoading, LoadingOptionsResolved} from 'element-plus';
|
|
|
// 重复请求队列
|
|
|
const pendingMap = new Map();
|
|
|
// 全局loading
|
|
|
const LoadingInstance = {
|
|
|
- _target: null as any,
|
|
|
- _count: 0,
|
|
|
+ _target: null as any,
|
|
|
+ _count: 0,
|
|
|
};
|
|
|
type customOptionsType = {
|
|
|
- repeat_request_cancel?: boolean; // 是否开启取消重复请求, 默认为 true
|
|
|
- loading?: boolean; // 是否开启全屏loading层效果, 默认为false
|
|
|
- reduct_data_format?: boolean; // 是否开启简洁的数据结构响应 减少一层data, 默认为true
|
|
|
- error_message_show?: boolean; // 是否开启接口错误信息展示,默认为true
|
|
|
- code_message_show?: boolean; // 是否开启code不为0时的信息提示, 默认为false
|
|
|
+ repeat_request_cancel?: boolean; // 是否开启取消重复请求, 默认为 true
|
|
|
+ loading?: boolean; // 是否开启全屏loading层效果, 默认为false
|
|
|
+ reduct_data_format?: boolean; // 是否开启简洁的数据结构响应 减少一层data, 默认为true
|
|
|
+ error_message_show?: boolean; // 是否开启接口错误信息展示,默认为true
|
|
|
+ code_message_show?: boolean; // 是否开启code不为0时的信息提示, 默认为false
|
|
|
};
|
|
|
export default function myAxios(axiosConfig: any, customOptions?: customOptionsType, loadingOptions?: LoadingOptionsResolved) {
|
|
|
- // 配置新建一个 axios 实例
|
|
|
- const service: AxiosInstance = axios.create({
|
|
|
- baseURL: import.meta.env.VITE_API_URL,
|
|
|
- timeout: 50000,
|
|
|
- headers: { 'Content-Type': 'application/json' },
|
|
|
- });
|
|
|
+ // 配置新建一个 axios 实例
|
|
|
+ const service: AxiosInstance = axios.create({
|
|
|
+ baseURL: import.meta.env.VITE_API_URL,
|
|
|
+ timeout: 50000,
|
|
|
+ headers: {'Content-Type': 'application/json'},
|
|
|
+ });
|
|
|
|
|
|
- // 自定义配置
|
|
|
- let custom_options = Object.assign(
|
|
|
- {
|
|
|
- repeat_request_cancel: true, // 是否开启取消重复请求, 默认为 true
|
|
|
- loading: false, // 是否开启全屏loading层效果, 默认为false
|
|
|
- reduct_data_format: true, // 是否开启简洁的数据结构响应 减少一层data, 默认为true
|
|
|
- error_message_show: true, // 是否开启接口错误信息展示,默认为true
|
|
|
- code_message_show: false, // 是否开启code不为0时的信息提示, 默认为false
|
|
|
- },
|
|
|
- customOptions
|
|
|
- );
|
|
|
+ // 自定义配置
|
|
|
+ let custom_options = Object.assign(
|
|
|
+ {
|
|
|
+ repeat_request_cancel: false, // 是否开启取消重复请求, 默认为 true
|
|
|
+ loading: false, // 是否开启全屏loading层效果, 默认为false
|
|
|
+ reduct_data_format: true, // 是否开启简洁的数据结构响应 减少一层data, 默认为true
|
|
|
+ error_message_show: true, // 是否开启接口错误信息展示,默认为true
|
|
|
+ code_message_show: false, // 是否开启code不为0时的信息提示, 默认为false
|
|
|
+ },
|
|
|
+ customOptions
|
|
|
+ );
|
|
|
|
|
|
- // 添加请求拦截器
|
|
|
- service.interceptors.request.use(
|
|
|
- async (config: any) => {
|
|
|
- removePending(config);
|
|
|
- custom_options.repeat_request_cancel && addPending(config);
|
|
|
- // 创建loading实例
|
|
|
- if (custom_options.loading) {
|
|
|
- LoadingInstance._count++;
|
|
|
- if (LoadingInstance._count === 1) {
|
|
|
- LoadingInstance._target = ElLoading.service(loadingOptions);
|
|
|
- }
|
|
|
- }
|
|
|
- // 在发送请求之前做些什么 token
|
|
|
- if (sessionStorage.getItem('token')) {
|
|
|
- (<any>config.headers)['Authorization'] = `Bearer ${sessionStorage.getItem('token')}`;
|
|
|
- }
|
|
|
- return config;
|
|
|
- },
|
|
|
- async (error: AxiosError) => {
|
|
|
- return Promise.reject(error);
|
|
|
- }
|
|
|
- );
|
|
|
- // 添加响应拦截器
|
|
|
- service.interceptors.response.use(
|
|
|
- (response: AxiosResponse): any => {
|
|
|
- removePending(response.config);
|
|
|
- custom_options.loading && closeLoading(custom_options); // 关闭loading
|
|
|
- // 对响应数据做点什么
|
|
|
- if (custom_options.code_message_show && response.data && response.data.code !== 0) {
|
|
|
- ElMessage({
|
|
|
- type: 'error',
|
|
|
- message: response.data.message,
|
|
|
- });
|
|
|
- return Promise.reject(response.data); // code不等于0, 页面具体逻辑就不执行了
|
|
|
- }
|
|
|
- return custom_options.reduct_data_format ? response.data : response;
|
|
|
- },
|
|
|
- async (error: AxiosError): Promise<never> => {
|
|
|
- error.config && removePending(error.config);
|
|
|
- custom_options.loading && closeLoading(custom_options); // 关闭loading
|
|
|
- custom_options.error_message_show && httpErrorStatusHandle(error); // 处理错误状态码
|
|
|
- return Promise.reject(error); // 错误继续返回给到具体页面
|
|
|
- }
|
|
|
- );
|
|
|
+ // 添加请求拦截器
|
|
|
+ service.interceptors.request.use(
|
|
|
+ async (config: any) => {
|
|
|
+ removePending(config);
|
|
|
+ custom_options.repeat_request_cancel && addPending(config);
|
|
|
+ // 创建loading实例
|
|
|
+ if (custom_options.loading) {
|
|
|
+ LoadingInstance._count++;
|
|
|
+ if (LoadingInstance._count === 1) {
|
|
|
+ LoadingInstance._target = ElLoading.service(loadingOptions);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 在发送请求之前做些什么 token
|
|
|
+ if (sessionStorage.getItem('token')) {
|
|
|
+ (<any>config.headers)['Authorization'] = `Bearer ${sessionStorage.getItem('token')}`;
|
|
|
+ }
|
|
|
+ return config;
|
|
|
+ },
|
|
|
+ async (error: AxiosError) => {
|
|
|
+ return Promise.reject(error);
|
|
|
+ }
|
|
|
+ );
|
|
|
+ // 添加响应拦截器
|
|
|
+ service.interceptors.response.use(
|
|
|
+ (response: AxiosResponse): any => {
|
|
|
+ removePending(response.config);
|
|
|
+ custom_options.loading && closeLoading(custom_options); // 关闭loading
|
|
|
+ // 对响应数据做点什么
|
|
|
+ if (custom_options.code_message_show && response.data && response.data.code !== 0) {
|
|
|
+ ElMessage({
|
|
|
+ type: 'error',
|
|
|
+ message: response.data.message,
|
|
|
+ });
|
|
|
+ return Promise.reject(response.data); // code不等于0, 页面具体逻辑就不执行了
|
|
|
+ }
|
|
|
+ return custom_options.reduct_data_format ? response.data : response;
|
|
|
+ },
|
|
|
+ async (error: AxiosError): Promise<never> => {
|
|
|
+ error.config && removePending(error.config);
|
|
|
+ custom_options.loading && closeLoading(custom_options); // 关闭loading
|
|
|
+ custom_options.error_message_show && httpErrorStatusHandle(error); // 处理错误状态码
|
|
|
+ return Promise.reject(error); // 错误继续返回给到具体页面
|
|
|
+ }
|
|
|
+ );
|
|
|
|
|
|
- return service(axiosConfig);
|
|
|
+ return service(axiosConfig);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -87,80 +87,81 @@ export default function myAxios(axiosConfig: any, customOptions?: customOptionsT
|
|
|
* @param {*} error
|
|
|
*/
|
|
|
function httpErrorStatusHandle(error: any) {
|
|
|
- // 设置一个变量 处理同一时间多个错误重复弹窗口
|
|
|
- let tokenAbnormal: boolean = false;
|
|
|
- // 处理被取消的请求
|
|
|
- if (axios.isCancel(error)) return;
|
|
|
- let message = '';
|
|
|
- if (error && error.response) {
|
|
|
- switch (error.response.status) {
|
|
|
- case 302:
|
|
|
- message = '接口重定向了!';
|
|
|
- break;
|
|
|
- case 400:
|
|
|
- message = '参数不正确!';
|
|
|
- break;
|
|
|
- case 401:
|
|
|
- if (!tokenAbnormal) {
|
|
|
- tokenAbnormal = true;
|
|
|
- // 弹出框
|
|
|
- ElMessageBox.alert('你已被登出,请重新登录', '提示', { type: 'warning' })
|
|
|
- .then(() => {
|
|
|
- window.localStorage.clear(); // 清除本地存储
|
|
|
+ // 设置一个变量 处理同一时间多个错误重复弹窗口
|
|
|
+ let tokenAbnormal: boolean = false;
|
|
|
+ // 处理被取消的请求
|
|
|
+ if (axios.isCancel(error)) return;
|
|
|
+ let message = '';
|
|
|
+ if (error && error.response) {
|
|
|
+ switch (error.response.status) {
|
|
|
+ case 302:
|
|
|
+ message = '接口重定向了!';
|
|
|
+ break;
|
|
|
+ case 400:
|
|
|
+ message = '参数不正确!';
|
|
|
+ break;
|
|
|
+ case 401:
|
|
|
+ if (!tokenAbnormal) {
|
|
|
+ tokenAbnormal = true;
|
|
|
+ // 弹出框
|
|
|
+ ElMessageBox.alert('你已被登出,请重新登录', '提示', {type: 'warning'})
|
|
|
+ .then(() => {
|
|
|
+ window.localStorage.clear(); // 清除本地存储
|
|
|
window.sessionStorage.clear(); // 清除临时存储
|
|
|
|
|
|
- location.reload(); //刷新页面
|
|
|
- })
|
|
|
- .catch((): void => {});
|
|
|
- // 设置定时器,确保下次异常时弹出框正常弹出
|
|
|
- setTimeout(() => {
|
|
|
- tokenAbnormal = false;
|
|
|
- }, 3000);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 403:
|
|
|
- message = '您没有权限操作!';
|
|
|
- break;
|
|
|
- case 404:
|
|
|
- message = `请求地址出错: ${error.response.config.url}`;
|
|
|
- break; // 在正确域名下
|
|
|
- case 408:
|
|
|
- message = '请求超时!';
|
|
|
- break;
|
|
|
- case 409:
|
|
|
- message = '系统已存在相同数据!';
|
|
|
- break;
|
|
|
- case 500:
|
|
|
- if (error.response?.data.message) message = error.response.data.message;
|
|
|
- else message = '服务器内部错误!';
|
|
|
- break;
|
|
|
- case 501:
|
|
|
- message = '服务未实现!';
|
|
|
- break;
|
|
|
- case 502:
|
|
|
- message = '网关错误!';
|
|
|
- break;
|
|
|
- case 503:
|
|
|
- message = '服务不可用!';
|
|
|
- break;
|
|
|
- case 504:
|
|
|
- message = '服务暂时无法访问,请稍后再试!';
|
|
|
- break;
|
|
|
- case 505:
|
|
|
- message = 'HTTP版本不受支持!';
|
|
|
- break;
|
|
|
- default:
|
|
|
- message = '异常问题,请联系管理员!';
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- if (error.message.includes('timeout')) message = '网络请求超时!';
|
|
|
- if (error.message.includes('Network')) message = window.navigator.onLine ? '服务端异常!' : '您断网了!';
|
|
|
+ location.reload(); //刷新页面
|
|
|
+ })
|
|
|
+ .catch((): void => {
|
|
|
+ });
|
|
|
+ // 设置定时器,确保下次异常时弹出框正常弹出
|
|
|
+ setTimeout(() => {
|
|
|
+ tokenAbnormal = false;
|
|
|
+ }, 3000);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 403:
|
|
|
+ message = '您没有权限操作!';
|
|
|
+ break;
|
|
|
+ case 404:
|
|
|
+ message = `请求地址出错: ${error.response.config.url}`;
|
|
|
+ break; // 在正确域名下
|
|
|
+ case 408:
|
|
|
+ message = '请求超时!';
|
|
|
+ break;
|
|
|
+ case 409:
|
|
|
+ message = '系统已存在相同数据!';
|
|
|
+ break;
|
|
|
+ case 500:
|
|
|
+ if (error.response?.data.message) message = error.response.data.message;
|
|
|
+ else message = '服务器内部错误!';
|
|
|
+ break;
|
|
|
+ case 501:
|
|
|
+ message = '服务未实现!';
|
|
|
+ break;
|
|
|
+ case 502:
|
|
|
+ message = '网关错误!';
|
|
|
+ break;
|
|
|
+ case 503:
|
|
|
+ message = '服务不可用!';
|
|
|
+ break;
|
|
|
+ case 504:
|
|
|
+ message = '服务暂时无法访问,请稍后再试!';
|
|
|
+ break;
|
|
|
+ case 505:
|
|
|
+ message = 'HTTP版本不受支持!';
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ message = '异常问题,请联系管理员!';
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (error.message.includes('timeout')) message = '网络请求超时!';
|
|
|
+ if (error.message.includes('Network')) message = window.navigator.onLine ? '服务端异常!' : '您断网了!';
|
|
|
|
|
|
- ElMessage({
|
|
|
- type: 'error',
|
|
|
- message,
|
|
|
- });
|
|
|
+ ElMessage({
|
|
|
+ type: 'error',
|
|
|
+ message,
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -168,11 +169,11 @@ function httpErrorStatusHandle(error: any) {
|
|
|
* @param {*} _options
|
|
|
*/
|
|
|
function closeLoading(_options: any) {
|
|
|
- if (_options.loading && LoadingInstance._count > 0) LoadingInstance._count--;
|
|
|
- if (LoadingInstance._count === 0) {
|
|
|
- LoadingInstance._target.close();
|
|
|
- LoadingInstance._target = null;
|
|
|
- }
|
|
|
+ if (_options.loading && LoadingInstance._count > 0) LoadingInstance._count--;
|
|
|
+ if (LoadingInstance._count === 0) {
|
|
|
+ LoadingInstance._target.close();
|
|
|
+ LoadingInstance._target = null;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -180,14 +181,14 @@ function closeLoading(_options: any) {
|
|
|
* @param {*} config
|
|
|
*/
|
|
|
function addPending(config: AxiosRequestConfig) {
|
|
|
- const pendingKey = getPendingKey(config);
|
|
|
- config.cancelToken =
|
|
|
- config.cancelToken ||
|
|
|
- new axios.CancelToken((cancel) => {
|
|
|
- if (!pendingMap.has(pendingKey)) {
|
|
|
- pendingMap.set(pendingKey, cancel);
|
|
|
- }
|
|
|
- });
|
|
|
+ const pendingKey = getPendingKey(config);
|
|
|
+ config.cancelToken =
|
|
|
+ config.cancelToken ||
|
|
|
+ new axios.CancelToken((cancel) => {
|
|
|
+ if (!pendingMap.has(pendingKey)) {
|
|
|
+ pendingMap.set(pendingKey, cancel);
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -195,13 +196,13 @@ function addPending(config: AxiosRequestConfig) {
|
|
|
* @param {*} config
|
|
|
*/
|
|
|
function removePending(config: AxiosRequestConfig) {
|
|
|
- const pendingKey = getPendingKey(config);
|
|
|
- if (pendingMap.has(pendingKey)) {
|
|
|
- const cancelToken = pendingMap.get(pendingKey);
|
|
|
- // 如你不明白此处为什么需要传递pendingKey可以看文章下方的补丁解释
|
|
|
- cancelToken(pendingKey);
|
|
|
- pendingMap.delete(pendingKey);
|
|
|
- }
|
|
|
+ const pendingKey = getPendingKey(config);
|
|
|
+ if (pendingMap.has(pendingKey)) {
|
|
|
+ const cancelToken = pendingMap.get(pendingKey);
|
|
|
+ // 如你不明白此处为什么需要传递pendingKey可以看文章下方的补丁解释
|
|
|
+ cancelToken(pendingKey);
|
|
|
+ pendingMap.delete(pendingKey);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -210,7 +211,7 @@ function removePending(config: AxiosRequestConfig) {
|
|
|
* @returns
|
|
|
*/
|
|
|
function getPendingKey(config: AxiosRequestConfig) {
|
|
|
- let { url, method, params, data } = config;
|
|
|
- // if (typeof data === 'string') data = JSON.parse(data); // response里面返回的config.data是个字符串对象
|
|
|
- return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&');
|
|
|
+ let {url, method, params, data} = config;
|
|
|
+ // if (typeof data === 'string') data = JSON.parse(data); // response里面返回的config.data是个字符串对象
|
|
|
+ return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&');
|
|
|
}
|