import type { CreateAxiosOptions } from './axiosTransform' import type { AxiosRequestConfig, AxiosInstance, AxiosResponse, AxiosError, } from 'axios' import type { RequestOptions, RequestResult } from '@vben/types' import axios from 'axios' import qs from 'qs' import { isFunction, cloneDeep } from '@vben/utils' import { AxiosCanceler } from './axiosCancel' import { ContentTypeEnum, RequestEnum } from './constants' export * from './axiosTransform' /** * @description: axios module */ export class VAxios { private axiosInstance: AxiosInstance private options: CreateAxiosOptions constructor(options: CreateAxiosOptions) { this.options = options this.axiosInstance = axios.create(options) this.setupInterceptors() } /** * @description: Create axios instance */ private createAxios(config: CreateAxiosOptions): void { this.axiosInstance = axios.create(config) } private getTransform() { const { transform } = this.options return transform } getAxios(): AxiosInstance { return this.axiosInstance } /** * @description: Reconfigure axios */ configAxios(options: CreateAxiosOptions) { if (!this.axiosInstance) { return } const opt: CreateAxiosOptions = Object.assign({}, this.options, options) this.createAxios(opt) this.options = opt this.setupInterceptors() } /** * @description: Set general header */ setHeader(headers: any): void { if (!this.axiosInstance) { return } Object.assign(this.axiosInstance.defaults.headers, headers) } /** * @description: Interceptor configuration */ private setupInterceptors() { const transform = this.getTransform() if (!transform) { return } const { requestInterceptors, requestInterceptorsCatch, responseInterceptors, responseInterceptorsCatch, } = transform const axiosCanceler = new AxiosCanceler() // Request interceptor configuration processing this.axiosInstance.interceptors.request.use( (config: AxiosRequestConfig) => { // If cancel repeat request is turned on, then cancel repeat request is prohibited // @ts-ignore const { ignoreCancelToken } = config.requestOptions const ignoreCancel = ignoreCancelToken !== undefined ? ignoreCancelToken : this.options.requestOptions?.ignoreCancelToken !ignoreCancel && axiosCanceler.addPending(config) if (requestInterceptors && isFunction(requestInterceptors)) { config = requestInterceptors(config, this.options) } return config }, undefined, ) // Request interceptor error capture requestInterceptorsCatch && isFunction(requestInterceptorsCatch) && this.axiosInstance.interceptors.request.use( undefined, requestInterceptorsCatch, ) // Response result interceptor processing this.axiosInstance.interceptors.response.use((res: AxiosResponse) => { res && axiosCanceler.removePending(res.config) if (responseInterceptors && isFunction(responseInterceptors)) { res = responseInterceptors(res) } return res }, undefined) // Response result interceptor error capture responseInterceptorsCatch && isFunction(responseInterceptorsCatch) && this.axiosInstance.interceptors.response.use( undefined, responseInterceptorsCatch, ) } // support form-data supportFormData(config: AxiosRequestConfig) { const headers = config.headers || this.options.headers const contentType = headers?.['Content-Type'] || headers?.['content-type'] if ( contentType !== ContentTypeEnum.FORM_URLENCODED || !Reflect.has(config, 'data') || config.method?.toUpperCase() === RequestEnum.GET ) { return config } return { ...config, data: qs.stringify(config.data, { arrayFormat: 'brackets' }), } } get( config: AxiosRequestConfig, options?: RequestOptions, ): Promise { return this.request({ ...config, method: 'GET' }, options) } post( config: AxiosRequestConfig, options?: RequestOptions, ): Promise { return this.request({ ...config, method: 'POST' }, options) } put( config: AxiosRequestConfig, options?: RequestOptions, ): Promise { return this.request({ ...config, method: 'PUT' }, options) } delete( config: AxiosRequestConfig, options?: RequestOptions, ): Promise { return this.request({ ...config, method: 'DELETE' }, options) } request( config: AxiosRequestConfig, options?: RequestOptions, ): Promise { let conf: CreateAxiosOptions = cloneDeep(config) const transform = this.getTransform() const { requestOptions } = this.options const opt: RequestOptions = Object.assign({}, requestOptions, options) const { beforeRequestHook, requestCatchHook, transformRequestHook } = transform || {} if (beforeRequestHook && isFunction(beforeRequestHook)) { conf = beforeRequestHook(conf, opt) } conf.requestOptions = opt conf = this.supportFormData(conf) return new Promise((resolve, reject) => { this.axiosInstance .request>(conf) .then((res: AxiosResponse) => { if (transformRequestHook && isFunction(transformRequestHook)) { try { const ret = transformRequestHook(res, opt) resolve(ret) } catch (err) { reject(err || new Error('request error!')) } return } resolve(res as unknown as Promise) }) .catch((e: Error | AxiosError) => { if (requestCatchHook && isFunction(requestCatchHook)) { reject(requestCatchHook(e, opt)) return } if (axios.isAxiosError(e)) { // rewrite error message from axios in here } reject(e) }) }) } }