class版本
request.ts
import axios, { InternalAxiosRequestConfig } from 'axios';
import axiosCancel from './axiosCancelClass';
const instance = axios.create({
baseURL: 'http://localhost:8889/',
timeout: 10 * 1000,
});
instance.interceptors.request.use(
config => {
axiosCancel.pushCancel(config);
return config;
},
error => {
if (error.config) {
axiosCancel.deleteCancel(error.config);
}
return Promise.reject(error);
},
);
instance.interceptors.response.use(
config => {
axiosCancel.deleteCancel(config.config);
return config;
},
error => {
if (error.config) {
axiosCancel.deleteCancel(error.config);
}
return new Promise(() => {});
},
);
export default instance;
axiosCancel.ts
import axios, { InternalAxiosRequestConfig } from 'axios';
type CancelAllAxios = {
all?: boolean;
config?: Option | Option[];
};
type Option = {
url?: string;
method: string;
reg?: RegExp;
};
type WhiteList = Option[];
type Config = {
url: string;
method: string;
};
class axiosCancel {
whiteList: WhiteList;
#Mapping: Map<string, Function>;
constructor() {
this.whiteList = [];
this.#Mapping = new Map();
}
#cancelAxiosSingle(config: InternalAxiosRequestConfig): void {
let key = this.#getMapKey(config);
let cancel = this.#Mapping.get(key);
cancel && cancel();
}
#isIncludes(arr: WhiteList, config: Config): boolean {
let urls = arr.filter(item => {
if (
item.url &&
Object.prototype.toString.call(item.url) === '[object String]'
) {
let result =
(item.url as string) === config.url &&
item.method.toLowerCase() === config.method.toLowerCase();
return result;
}
if (
item.reg &&
Object.prototype.toString.call(item.reg) === '[object RegExp]'
) {
let result =
(item.reg as RegExp).test(config.url as string) &&
item.method.toLowerCase() === config.method.toLowerCase();
return result;
}
return false;
});
return urls.length > 0;
}
#getMapKey(config: InternalAxiosRequestConfig): string {
const key = `${config?.url}&${config?.method?.toLowerCase()}`;
return key;
}
#addCancel(config: InternalAxiosRequestConfig): void {
config.cancelToken =
config.cancelToken ??
new axios.CancelToken(cancel => {
this.#Mapping.set(this.#getMapKey(config), cancel);
});
}
pushCancel(config: InternalAxiosRequestConfig): void {
if (this.#isIncludes(this.whiteList, config as Config)) {
return;
}
let isCancelBefore: boolean =
config?.data?.cancelBefore ?? config?.params?.cancelBefore ?? true;
if (config?.data) {
config.data && Reflect.deleteProperty(config.data, 'cancelBefore');
} else {
config.params &&
Reflect.deleteProperty(config.params, 'cancelBefore');
}
let key = this.#getMapKey(config);
if (isCancelBefore) {
if (this.#Mapping.has(key)) {
this.#cancelAxiosSingle(config);
this.deleteCancel(config);
}
this.#addCancel(config);
} else {
if (this.#Mapping.has(key)) {
config.cancelToken = new axios.CancelToken(cancel => {
cancel();
});
} else {
this.#addCancel(config);
}
}
}
deleteCancel(config: InternalAxiosRequestConfig): void {
let key = this.#getMapKey(config);
this.#Mapping.delete(key);
}
cancelAxios(config: CancelAllAxios): Promise<void> {
for (const [key, cancel] of this.#Mapping) {
let [url, method] = key.split('&');
let currentConfig = {
url,
method,
};
if (config.all === true) {
cancel('');
this.#Mapping.delete(key);
} else {
if (
Object.prototype.toString.call(config.config) ===
'[object Array]'
) {
if (
this.#isIncludes(
config.config as Option[],
currentConfig,
)
) {
cancel('');
this.#Mapping.delete(key);
}
} else if (
Object.prototype.toString.call(config.config) ===
'[object Object]'
) {
if (
this.#isIncludes(
[config.config] as Option[],
currentConfig,
)
) {
cancel('');
this.#Mapping.delete(key);
}
}
}
}
return Promise.resolve();
}
}
let AxiosCancel = new axiosCancel();
export default AxiosCancel;
index.vue
axiosCancel.whiteList.push({
url: '/api/plice',
method: 'post',
});
axiosCancel.whiteList.push({
method: 'get',
reg: /\/api\/plice/,
});
const cancel = (): void => {
axiosCancel.cancelAxios({
all: true,
});
};
const cancel = (): void => {
axiosCancel.cancelAxios({
config: {
method: 'get',
url: '/api/plice',
},
});
};