import Axios, { AxiosRequestConfig, CancelTokenStatic, AxiosInstance } from "axios"; import NProgress from "../progress"; import { genConfig } from "./config"; import { transformConfigByMethod } from "./utils"; import { cancelTokenType, RequestMethods, EnclosureHttpRequestConfig, EnclosureHttpResoponse, EnclosureHttpError } from "./types.d"; class EnclosureHttp { constructor() { this.httpInterceptorsRequest(); this.httpInterceptorsResponse(); } // 初始化配置对象 private static initConfig: EnclosureHttpRequestConfig = {}; // 保存当前Axios实例对象 private static axiosInstance: AxiosInstance = Axios.create(genConfig()); // 保存 EnclosureHttp实例 private static EnclosureHttpInstance: EnclosureHttp; // axios取消对象 private CancelToken: CancelTokenStatic = Axios.CancelToken; // 取消的凭证数组 private sourceTokenList: Array = []; // 记录当前这一次cancelToken的key private currentCancelTokenKey = ""; private beforeRequestCallback: EnclosureHttpRequestConfig["beforeRequestCallback"] = undefined; private beforeResponseCallback: EnclosureHttpRequestConfig["beforeResponseCallback"] = undefined; public get cancelTokenList(): Array { return this.sourceTokenList; } // eslint-disable-next-line class-methods-use-this public set cancelTokenList(value) { throw new Error("cancelTokenList不允许赋值"); } /** * @description 私有构造不允许实例化 * @returns void 0 */ // constructor() {} /** * @description 生成唯一取消key * @param config axios配置 * @returns string */ // eslint-disable-next-line class-methods-use-this private static genUniqueKey(config: EnclosureHttpRequestConfig): string { return `${config.url}--${JSON.stringify(config.data)}`; } /** * @description 取消重复请求 * @returns void 0 */ private cancelRepeatRequest(): void { const temp: { [key: string]: boolean } = {}; this.sourceTokenList = this.sourceTokenList.reduce>( (res: Array, cancelToken: cancelTokenType) => { const { cancelKey, cancelExecutor } = cancelToken; if (!temp[cancelKey]) { temp[cancelKey] = true; res.push(cancelToken); } else { cancelExecutor(); } return res; }, [] ); } /** * @description 删除指定的CancelToken * @returns void 0 */ private deleteCancelTokenByCancelKey(cancelKey: string): void { this.sourceTokenList = this.sourceTokenList.length < 1 ? this.sourceTokenList.filter( cancelToken => cancelToken.cancelKey !== cancelKey ) : []; } /** * @description 拦截请求 * @returns void 0 */ private httpInterceptorsRequest(): void { EnclosureHttp.axiosInstance.interceptors.request.use( (config: EnclosureHttpRequestConfig) => { const $config = config; NProgress.start(); // 每次切换页面时,调用进度条 const cancelKey = EnclosureHttp.genUniqueKey($config); $config.cancelToken = new this.CancelToken( (cancelExecutor: (cancel: any) => void) => { this.sourceTokenList.push({ cancelKey, cancelExecutor }); } ); this.cancelRepeatRequest(); this.currentCancelTokenKey = cancelKey; // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉 if (typeof this.beforeRequestCallback === "function") { this.beforeRequestCallback($config); this.beforeRequestCallback = undefined; return $config; } if (EnclosureHttp.initConfig.beforeRequestCallback) { EnclosureHttp.initConfig.beforeRequestCallback($config); return $config; } return $config; }, error => { return Promise.reject(error); } ); } /** * @description 清空当前cancelTokenList * @returns void 0 */ public clearCancelTokenList(): void { this.sourceTokenList.length = 0; } /** * @description 拦截相应 * @returns void 0 */ private httpInterceptorsResponse(): void { const instance = EnclosureHttp.axiosInstance; instance.interceptors.response.use( (response: EnclosureHttpResoponse) => { // 请求每次成功一次就删除当前canceltoken标记 const cancelKey = EnclosureHttp.genUniqueKey(response.config); this.deleteCancelTokenByCancelKey(cancelKey); // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉 if (typeof this.beforeResponseCallback === "function") { this.beforeResponseCallback(response); this.beforeResponseCallback = undefined; return response.data; } if (EnclosureHttp.initConfig.beforeResponseCallback) { EnclosureHttp.initConfig.beforeResponseCallback(response); return response.data; } NProgress.done(); return response.data; }, (error: EnclosureHttpError) => { const $error = error; // 判断当前的请求中是否在 取消token数组理存在,如果存在则移除(单次请求流程) if (this.currentCancelTokenKey) { const haskey = this.sourceTokenList.filter( cancelToken => cancelToken.cancelKey === this.currentCancelTokenKey ).length; if (haskey) { this.sourceTokenList = this.sourceTokenList.filter( cancelToken => cancelToken.cancelKey !== this.currentCancelTokenKey ); this.currentCancelTokenKey = ""; } } $error.isCancelRequest = Axios.isCancel($error); // 所有的响应异常 区分来源为取消请求/非取消请求 return Promise.reject($error); } ); } public request( method: RequestMethods, url: string, param?: AxiosRequestConfig, axiosConfig?: EnclosureHttpRequestConfig ): Promise { const config = transformConfigByMethod(param, { method, url, ...axiosConfig } as EnclosureHttpRequestConfig); // 单独处理自定义请求/响应回掉 if (axiosConfig?.beforeRequestCallback) { this.beforeRequestCallback = axiosConfig.beforeRequestCallback; } if (axiosConfig?.beforeResponseCallback) { this.beforeResponseCallback = axiosConfig.beforeResponseCallback; } return new Promise((resolve, reject) => { EnclosureHttp.axiosInstance .request(config) .then((response: EnclosureHttpResoponse) => { resolve(response); }) .catch((error: any) => { reject(error); }); }); } public post( url: string, params?: T, config?: EnclosureHttpRequestConfig ): Promise { return this.request("post", url, params, config); } public get( url: string, params?: T, config?: EnclosureHttpRequestConfig ): Promise { return this.request("get", url, params, config); } } export default EnclosureHttp;