Kirk Lin
2023-04-06 ccaa84c3058c7f7ff5ac9ce14ec1d951c87fa5a6
提交 | 用户 | age
ccaa84 1 import type {
KL 2   AxiosRequestConfig,
3   AxiosInstance,
4   AxiosResponse,
5   AxiosError,
6   InternalAxiosRequestConfig,
7 } from 'axios';
590288 8 import type { RequestOptions, Result, UploadFileParams } from '/#/axios';
970d40 9 import type { CreateAxiosOptions } from './axiosTransform';
2f6253 10 import axios from 'axios';
970d40 11 import qs from 'qs';
2f6253 12 import { AxiosCanceler } from './axiosCancel';
13 import { isFunction } from '/@/utils/is';
935d4f 14 import { cloneDeep } from 'lodash-es';
8e5a6b 15 import { ContentTypeEnum, RequestEnum } from '/@/enums/httpEnum';
2f6253 16
17 export * from './axiosTransform';
18
19 /**
589409 20  * @description:  axios module
2f6253 21  */
22 export class VAxios {
23   private axiosInstance: AxiosInstance;
ecfb70 24   private readonly options: CreateAxiosOptions;
2f6253 25
26   constructor(options: CreateAxiosOptions) {
27     this.options = options;
28     this.axiosInstance = axios.create(options);
29     this.setupInterceptors();
30   }
31
32   /**
589409 33    * @description:  Create axios instance
2f6253 34    */
35   private createAxios(config: CreateAxiosOptions): void {
36     this.axiosInstance = axios.create(config);
37   }
38
39   private getTransform() {
40     const { transform } = this.options;
41     return transform;
42   }
43
44   getAxios(): AxiosInstance {
45     return this.axiosInstance;
46   }
47
48   /**
589409 49    * @description: Reconfigure axios
2f6253 50    */
51   configAxios(config: CreateAxiosOptions) {
52     if (!this.axiosInstance) {
53       return;
54     }
55     this.createAxios(config);
56   }
57
58   /**
589409 59    * @description: Set general header
2f6253 60    */
61   setHeader(headers: any): void {
62     if (!this.axiosInstance) {
63       return;
64     }
65     Object.assign(this.axiosInstance.defaults.headers, headers);
66   }
67
68   /**
19dc88 69    * @description: Interceptor configuration 拦截器配置
2f6253 70    */
71   private setupInterceptors() {
ccaa84 72     // const transform = this.getTransform();
KL 73     const {
74       axiosInstance,
75       options: { transform },
76     } = this;
2f6253 77     if (!transform) {
78       return;
79     }
80     const {
81       requestInterceptors,
82       requestInterceptorsCatch,
83       responseInterceptors,
84       responseInterceptorsCatch,
85     } = transform;
86
87     const axiosCanceler = new AxiosCanceler();
88
589409 89     // Request interceptor configuration processing
ccaa84 90     this.axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
4ce1d5 91       // If cancel repeat request is turned on, then cancel repeat request is prohibited
ccaa84 92       const { requestOptions } = this.options;
KL 93       const ignoreCancelToken = requestOptions?.ignoreCancelToken ?? true;
3b8ca4 94
ccaa84 95       !ignoreCancelToken && axiosCanceler.addPending(config);
KL 96
2f6253 97       if (requestInterceptors && isFunction(requestInterceptors)) {
b6d5b0 98         config = requestInterceptors(config, this.options);
2f6253 99       }
100       return config;
101     }, undefined);
102
589409 103     // Request interceptor error capture
2f6253 104     requestInterceptorsCatch &&
105       isFunction(requestInterceptorsCatch) &&
106       this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch);
107
589409 108     // Response result interceptor processing
2f6253 109     this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => {
110       res && axiosCanceler.removePending(res.config);
111       if (responseInterceptors && isFunction(responseInterceptors)) {
112         res = responseInterceptors(res);
113       }
114       return res;
115     }, undefined);
116
589409 117     // Response result interceptor error capture
2f6253 118     responseInterceptorsCatch &&
119       isFunction(responseInterceptorsCatch) &&
136cbb 120       this.axiosInstance.interceptors.response.use(undefined, (error) => {
ccaa84 121         return responseInterceptorsCatch(axiosInstance, error);
136cbb 122       });
2f6253 123   }
124
746d4a 125   /**
589409 126    * @description:  File Upload
746d4a 127    */
J 128   uploadFile<T = any>(config: AxiosRequestConfig, params: UploadFileParams) {
129     const formData = new window.FormData();
935d4f 130     const customFilename = params.name || 'file';
E 131
132     if (params.filename) {
133       formData.append(customFilename, params.file, params.filename);
134     } else {
135       formData.append(customFilename, params.file);
136     }
2f6253 137
746d4a 138     if (params.data) {
J 139       Object.keys(params.data).forEach((key) => {
935d4f 140         const value = params.data![key];
746d4a 141         if (Array.isArray(value)) {
J 142           value.forEach((item) => {
143             formData.append(`${key}[]`, item);
144           });
145           return;
146         }
2f6253 147
935d4f 148         formData.append(key, params.data![key]);
746d4a 149       });
J 150     }
151
152     return this.axiosInstance.request<T>({
153       ...config,
154       method: 'POST',
155       data: formData,
156       headers: {
157         'Content-type': ContentTypeEnum.FORM_DATA,
a248e2 158         // @ts-ignore
746d4a 159         ignoreCancelToken: true,
J 160       },
161     });
162   }
2f6253 163
c41fa7 164   // support form-data
V 165   supportFormData(config: AxiosRequestConfig) {
5724bc 166     const headers = config.headers || this.options.headers;
c41fa7 167     const contentType = headers?.['Content-Type'] || headers?.['content-type'];
V 168
169     if (
170       contentType !== ContentTypeEnum.FORM_URLENCODED ||
171       !Reflect.has(config, 'data') ||
172       config.method?.toUpperCase() === RequestEnum.GET
173     ) {
174       return config;
175     }
176
177     return {
178       ...config,
e1b30a 179       data: qs.stringify(config.data, { arrayFormat: 'brackets' }),
c41fa7 180     };
V 181   }
182
a821d9 183   get<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
V 184     return this.request({ ...config, method: 'GET' }, options);
185   }
186
187   post<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
188     return this.request({ ...config, method: 'POST' }, options);
189   }
190
191   put<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
192     return this.request({ ...config, method: 'PUT' }, options);
193   }
194
195   delete<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
196     return this.request({ ...config, method: 'DELETE' }, options);
197   }
198
2f6253 199   request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
49b66e 200     let conf: CreateAxiosOptions = cloneDeep(config);
c70cf3 201     // cancelToken 如果被深拷贝,会导致最外层无法使用cancel方法来取消请求
ba2415 202     if (config.cancelToken) {
V 203       conf.cancelToken = config.cancelToken;
c70cf3 204     }
ba2415 205
2f6253 206     const transform = this.getTransform();
207
208     const { requestOptions } = this.options;
209
210     const opt: RequestOptions = Object.assign({}, requestOptions, options);
211
c0e40f 212     const { beforeRequestHook, requestCatchHook, transformResponseHook } = transform || {};
2f6253 213     if (beforeRequestHook && isFunction(beforeRequestHook)) {
214       conf = beforeRequestHook(conf, opt);
215     }
49b66e 216     conf.requestOptions = opt;
c41fa7 217
V 218     conf = this.supportFormData(conf);
11d3f3 219
2f6253 220     return new Promise((resolve, reject) => {
221       this.axiosInstance
222         .request<any, AxiosResponse<Result>>(conf)
223         .then((res: AxiosResponse<Result>) => {
c0e40f 224           if (transformResponseHook && isFunction(transformResponseHook)) {
b218f1 225             try {
c0e40f 226               const ret = transformResponseHook(res, opt);
b218f1 227               resolve(ret);
N 228             } catch (err) {
229               reject(err || new Error('request error!'));
230             }
2f6253 231             return;
232           }
b218f1 233           resolve(res as unknown as Promise<T>);
2f6253 234         })
72634f 235         .catch((e: Error | AxiosError) => {
a821d9 236           if (requestCatchHook && isFunction(requestCatchHook)) {
49b66e 237             reject(requestCatchHook(e, opt));
2f6253 238             return;
239           }
72634f 240           if (axios.isAxiosError(e)) {
C 241             // rewrite error message from axios in here
242           }
2f6253 243           reject(e);
244         });
245     });
246   }
247 }