Axios.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. import type { AxiosRequestConfig, AxiosInstance, AxiosResponse, AxiosError } from 'axios';
  2. import type { RequestOptions, Result, UploadFileParams } from '/#/axios';
  3. import type { CreateAxiosOptions } from './axiosTransform';
  4. import { useMessage } from '/@/hooks/web/useMessage';
  5. import axios from 'axios';
  6. import qs from 'qs';
  7. import { AxiosCanceler } from './axiosCancel';
  8. import { isFunction } from '/@/utils/is';
  9. import { cloneDeep } from 'lodash-es';
  10. import { ContentTypeEnum } from '/@/enums/httpEnum';
  11. import { RequestEnum } from '/@/enums/httpEnum';
  12. const { createMessage } = useMessage();
  13. import { downloadByData } from '/@/utils/file/download';
  14. export * from './axiosTransform';
  15. /**
  16. * @description: axios module
  17. */
  18. export class VAxios {
  19. private axiosInstance: AxiosInstance;
  20. private readonly options: CreateAxiosOptions;
  21. constructor(options: CreateAxiosOptions) {
  22. this.options = options;
  23. this.axiosInstance = axios.create(options);
  24. this.setupInterceptors();
  25. }
  26. /**
  27. * @description: Create axios instance
  28. */
  29. private createAxios(config: CreateAxiosOptions): void {
  30. this.axiosInstance = axios.create(config);
  31. }
  32. private getTransform() {
  33. const { transform } = this.options;
  34. return transform;
  35. }
  36. getAxios(): AxiosInstance {
  37. return this.axiosInstance;
  38. }
  39. /**
  40. * @description: Reconfigure axios
  41. */
  42. configAxios(config: CreateAxiosOptions) {
  43. if (!this.axiosInstance) {
  44. return;
  45. }
  46. this.createAxios(config);
  47. }
  48. /**
  49. * @description: Set general header
  50. */
  51. setHeader(headers: any): void {
  52. if (!this.axiosInstance) {
  53. return;
  54. }
  55. Object.assign(this.axiosInstance.defaults.headers, headers);
  56. }
  57. /**
  58. * @description: Interceptor configuration
  59. */
  60. private setupInterceptors() {
  61. const transform = this.getTransform();
  62. if (!transform) {
  63. return;
  64. }
  65. const {
  66. requestInterceptors,
  67. requestInterceptorsCatch,
  68. responseInterceptors,
  69. responseInterceptorsCatch,
  70. } = transform;
  71. const axiosCanceler = new AxiosCanceler();
  72. // Request interceptor configuration processing
  73. this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
  74. // If cancel repeat request is turned on, then cancel repeat request is prohibited
  75. const {
  76. // @ts-ignore
  77. headers: { ignoreCancelToken },
  78. } = config;
  79. const ignoreCancel =
  80. ignoreCancelToken !== undefined
  81. ? ignoreCancelToken
  82. : this.options.requestOptions?.ignoreCancelToken;
  83. !ignoreCancel && axiosCanceler.addPending(config);
  84. if (requestInterceptors && isFunction(requestInterceptors)) {
  85. config = requestInterceptors(config, this.options);
  86. }
  87. return config;
  88. }, undefined);
  89. // Request interceptor error capture
  90. requestInterceptorsCatch &&
  91. isFunction(requestInterceptorsCatch) &&
  92. this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch);
  93. // Response result interceptor processing
  94. this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => {
  95. res && axiosCanceler.removePending(res.config);
  96. if (responseInterceptors && isFunction(responseInterceptors)) {
  97. res = responseInterceptors(res);
  98. }
  99. return res;
  100. }, undefined);
  101. // Response result interceptor error capture
  102. responseInterceptorsCatch &&
  103. isFunction(responseInterceptorsCatch) &&
  104. this.axiosInstance.interceptors.response.use(undefined, responseInterceptorsCatch);
  105. }
  106. /**
  107. * @description: File Upload
  108. */
  109. uploadFile<T = any>(config: AxiosRequestConfig, params: UploadFileParams) {
  110. let conf: CreateAxiosOptions = cloneDeep(config);
  111. const formData = new window.FormData();
  112. const customFilename = params.name || 'file';
  113. if (params.filename) {
  114. formData.append(customFilename, params.file, params.filename);
  115. } else {
  116. const file = params.file.originFileObj || params.file;
  117. formData.append(customFilename, file || (params.data && params.data.file));
  118. }
  119. if (params.data) {
  120. Object.keys(params.data).forEach((key) => {
  121. const value = params.data![key];
  122. if (key == 'file' && !params.filename) {
  123. return;
  124. }
  125. if (Array.isArray(value)) {
  126. value.forEach((item) => {
  127. formData.append(`${key}[]`, item);
  128. });
  129. return;
  130. }
  131. if (params.data![key] == undefined) {
  132. formData.append(key, '');
  133. return;
  134. }
  135. formData.append(key, params.data![key]);
  136. });
  137. }
  138. const transform = this.getTransform();
  139. const { requestOptions } = this.options;
  140. const opt: RequestOptions = Object.assign({}, requestOptions);
  141. const { beforeRequestHook, requestCatchHook, transformRequestHook } = transform || {};
  142. if (beforeRequestHook && isFunction(beforeRequestHook)) {
  143. conf = beforeRequestHook(conf, opt);
  144. }
  145. conf = this.supportFormData(conf);
  146. console.log('supportFormData', conf);
  147. return new Promise((resolve, reject) => {
  148. this.axiosInstance
  149. .request<any, AxiosResponse<Result>>({
  150. ...conf,
  151. method: 'POST',
  152. data: formData,
  153. requestOptions,
  154. headers: {
  155. 'Content-type': ContentTypeEnum.FORM_DATA,
  156. // @ts-ignore
  157. ignoreCancelToken: true,
  158. },
  159. })
  160. .then((res: AxiosResponse<Result>) => {
  161. if (transformRequestHook && isFunction(transformRequestHook)) {
  162. try {
  163. const ret = transformRequestHook(res, opt);
  164. resolve(ret);
  165. } catch (err) {
  166. reject(err || new Error('request error!'));
  167. }
  168. return;
  169. }
  170. resolve(res as unknown as Promise<T>);
  171. })
  172. .catch((e: Error | AxiosError) => {
  173. if (requestCatchHook && isFunction(requestCatchHook)) {
  174. reject(requestCatchHook(e, opt));
  175. return;
  176. }
  177. if (axios.isAxiosError(e)) {
  178. // rewrite error message from axios in here
  179. }
  180. reject(e);
  181. });
  182. });
  183. }
  184. /**
  185. * @description: File Upload
  186. */
  187. downloadFile<T = any>(config: AxiosRequestConfig) {
  188. let conf: CreateAxiosOptions = cloneDeep(config);
  189. const { requestOptions } = this.options;
  190. const transform = this.getTransform();
  191. const opt: RequestOptions = Object.assign({}, requestOptions);
  192. const { beforeRequestHook, requestCatchHook, transformRequestHook } = transform || {};
  193. if (beforeRequestHook && isFunction(beforeRequestHook)) {
  194. conf = beforeRequestHook(conf, opt);
  195. }
  196. conf.requestOptions = opt;
  197. conf = this.supportFormData(conf);
  198. // return new Promise((resolve, reject) => {
  199. this.axiosInstance
  200. .request<any, AxiosResponse<Result>>(conf)
  201. .then((res: AxiosResponse<Result>) => {
  202. const resData = res.data;
  203. const fileReader = new FileReader();
  204. fileReader.onloadend = () => {
  205. // 此处两种判断返回信息的方法可选其一
  206. // 方法一:
  207. try {
  208. const jsonData = JSON.parse(fileReader.result); // 说明是普通对象数据,后台转换失败
  209. // 后台信息
  210. createMessage.error(jsonData.message);
  211. } catch (err) {
  212. // 解析成对象失败,说明是正常的文件流
  213. // 下载文件
  214. downloadByData(resData, config.fileName);
  215. }
  216. };
  217. fileReader.readAsText(resData);
  218. })
  219. .catch((e: Error | AxiosError) => {
  220. if (requestCatchHook && isFunction(requestCatchHook)) {
  221. requestCatchHook(e, opt);
  222. return;
  223. }
  224. console.log('Error', e);
  225. // reject(e);
  226. });
  227. // })
  228. }
  229. // support form-data
  230. supportFormData(config: AxiosRequestConfig) {
  231. const headers = config.headers || this.options.headers;
  232. const contentType = headers?.['Content-Type'] || headers?.['content-type'];
  233. if (
  234. contentType !== ContentTypeEnum.FORM_URLENCODED ||
  235. !Reflect.has(config, 'data') ||
  236. config.method?.toUpperCase() === RequestEnum.GET
  237. ) {
  238. return config;
  239. }
  240. return {
  241. ...config,
  242. data: qs.stringify(config.data, { arrayFormat: 'brackets' }),
  243. };
  244. }
  245. get<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
  246. return this.request({ ...config, method: 'GET' }, options);
  247. }
  248. post<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
  249. return this.request({ ...config, method: 'POST' }, options);
  250. }
  251. put<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
  252. return this.request({ ...config, method: 'PUT' }, options);
  253. }
  254. delete<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
  255. return this.request({ ...config, method: 'DELETE' }, options);
  256. }
  257. request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
  258. let conf: CreateAxiosOptions = cloneDeep(config);
  259. const transform = this.getTransform();
  260. const { requestOptions } = this.options;
  261. const opt: RequestOptions = Object.assign({}, requestOptions, options);
  262. const { beforeRequestHook, requestCatchHook, transformRequestHook } = transform || {};
  263. if (beforeRequestHook && isFunction(beforeRequestHook)) {
  264. conf = beforeRequestHook(conf, opt);
  265. }
  266. conf.requestOptions = opt;
  267. conf = this.supportFormData(conf);
  268. return new Promise((resolve, reject) => {
  269. this.axiosInstance
  270. .request<any, AxiosResponse<Result>>(conf)
  271. .then((res: AxiosResponse<Result>) => {
  272. if (transformRequestHook && isFunction(transformRequestHook)) {
  273. try {
  274. const ret = transformRequestHook(res, opt);
  275. resolve(ret);
  276. } catch (err) {
  277. reject(err || new Error('request error!'));
  278. }
  279. return;
  280. }
  281. resolve(res as unknown as Promise<T>);
  282. })
  283. .catch((e: Error | AxiosError) => {
  284. if (requestCatchHook && isFunction(requestCatchHook)) {
  285. reject(requestCatchHook(e, opt));
  286. return;
  287. }
  288. if (axios.isAxiosError(e)) {
  289. // rewrite error message from axios in here
  290. }
  291. reject(e);
  292. });
  293. });
  294. }
  295. }