import { RequestMethodsEnum } from '@/enums/requestEnums' import axios, { AxiosError, type AxiosInstance, type AxiosRequestConfig, type AxiosResponse } from 'axios' import { isFunction, merge, cloneDeep } from 'lodash' import axiosCancel from './cancel' import type { RequestData, RequestOptions } from './type' export class Axios { private axiosInstance: AxiosInstance private readonly config: AxiosRequestConfig private readonly options: RequestOptions constructor(config: AxiosRequestConfig) { this.config = config this.options = config.requestOptions this.axiosInstance = axios.create(config) this.setupInterceptors() } /** * @description 获取axios实例 */ getAxiosInstance() { return this.axiosInstance } /** * @description 设置拦截器 */ setupInterceptors() { if (!this.config.axiosHooks) { return } const { requestInterceptorsHook, requestInterceptorsCatchHook, responseInterceptorsHook, responseInterceptorsCatchHook } = this.config.axiosHooks this.axiosInstance.interceptors.request.use( (config) => { this.addCancelToken(config) if (isFunction(requestInterceptorsHook)) { config = requestInterceptorsHook(config) } return config }, (err: Error) => { if (isFunction(requestInterceptorsCatchHook)) { requestInterceptorsCatchHook(err) } return err } ) this.axiosInstance.interceptors.response.use( (response: AxiosResponse) => { this.removeCancelToken(response.config.url!) if (isFunction(responseInterceptorsHook)) { response = responseInterceptorsHook(response) } return response }, (err: AxiosError) => { if (isFunction(responseInterceptorsCatchHook)) { responseInterceptorsCatchHook(err) } if (err.code != AxiosError.ERR_CANCELED) { this.removeCancelToken(err.config?.url!) } if (err.code == AxiosError.ECONNABORTED || err.code == AxiosError.ERR_NETWORK) { return new Promise((resolve) => setTimeout(resolve, 500)).then(() => this.retryRequest(err) ) } return Promise.reject(err) } ) } /** * @description 添加CancelToken */ addCancelToken(config: AxiosRequestConfig) { const { ignoreCancelToken } = config.requestOptions !ignoreCancelToken && axiosCancel.add(config) } /** * @description 移除CancelToken */ removeCancelToken(url: string) { axiosCancel.remove(url) } /** * @description 重新请求 */ retryRequest(error: AxiosError) { const config = error.config const { retryCount, isOpenRetry } = config.requestOptions if (!isOpenRetry || config.method?.toUpperCase() == RequestMethodsEnum.POST) { return Promise.reject(error) } config.retryCount = config.retryCount ?? 0 if (config.retryCount >= retryCount) { return Promise.reject(error) } config.retryCount++ return this.axiosInstance.request(config) } /** * @description get请求 */ get( config: Partial, options?: Partial ): Promise { return this.request({ ...config, method: RequestMethodsEnum.GET }, options) } /** * @description post请求 */ post( config: Partial, options?: Partial ): Promise { return this.request({ ...config, method: RequestMethodsEnum.POST }, options) } /** * @description 请求函数 */ request( config: Partial, options?: Partial ): Promise { const opt: RequestOptions = merge({}, this.options, options) const axioxConfig: AxiosRequestConfig = { ...cloneDeep(config), requestOptions: opt } const { urlPrefix } = opt // 拼接请求前缀如api if (urlPrefix) { axioxConfig.url = `${urlPrefix}${config.url}` } return new Promise((resolve, reject) => { this.axiosInstance .request>>(axioxConfig) .then((res) => { resolve(res) }) .catch((err) => { reject(err) }) }) } }