request-client.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import type { AxiosInstance, AxiosResponse } from 'axios';
  2. import type { RequestClientConfig, RequestClientOptions } from './types';
  3. import { bindMethods, isString, merge } from '@vben/utils';
  4. import axios from 'axios';
  5. import qs from 'qs';
  6. import { FileDownloader } from './modules/downloader';
  7. import { InterceptorManager } from './modules/interceptor';
  8. import { SSE } from './modules/sse';
  9. import { FileUploader } from './modules/uploader';
  10. function getParamsSerializer(
  11. paramsSerializer: RequestClientOptions['paramsSerializer'],
  12. ) {
  13. if (isString(paramsSerializer)) {
  14. switch (paramsSerializer) {
  15. case 'brackets': {
  16. return (params: any) =>
  17. qs.stringify(params, { arrayFormat: 'brackets' });
  18. }
  19. case 'comma': {
  20. return (params: any) => qs.stringify(params, { arrayFormat: 'comma' });
  21. }
  22. case 'indices': {
  23. return (params: any) =>
  24. qs.stringify(params, { arrayFormat: 'indices' });
  25. }
  26. case 'repeat': {
  27. return (params: any) => qs.stringify(params, { arrayFormat: 'repeat' });
  28. }
  29. }
  30. }
  31. return paramsSerializer;
  32. }
  33. class RequestClient {
  34. public addRequestInterceptor: InterceptorManager['addRequestInterceptor'];
  35. public addResponseInterceptor: InterceptorManager['addResponseInterceptor'];
  36. public download: FileDownloader['download'];
  37. public readonly instance: AxiosInstance;
  38. // 是否正在刷新token
  39. public isRefreshing = false;
  40. public postSSE: SSE['postSSE'];
  41. // 刷新token队列
  42. public refreshTokenQueue: ((token: string) => void)[] = [];
  43. public requestSSE: SSE['requestSSE'];
  44. public upload: FileUploader['upload'];
  45. /**
  46. * 构造函数,用于创建Axios实例
  47. * @param options - Axios请求配置,可选
  48. */
  49. constructor(options: RequestClientOptions = {}) {
  50. // 合并默认配置和传入的配置
  51. const defaultConfig: RequestClientOptions = {
  52. headers: {
  53. 'Content-Type': 'application/json;charset=utf-8',
  54. },
  55. responseReturn: 'raw',
  56. // 默认超时时间
  57. timeout: 10_000,
  58. };
  59. const { ...axiosConfig } = options;
  60. const requestConfig = merge(axiosConfig, defaultConfig);
  61. requestConfig.paramsSerializer = getParamsSerializer(
  62. requestConfig.paramsSerializer,
  63. );
  64. this.instance = axios.create(requestConfig);
  65. bindMethods(this);
  66. // 实例化拦截器管理器
  67. const interceptorManager = new InterceptorManager(this.instance);
  68. this.addRequestInterceptor =
  69. interceptorManager.addRequestInterceptor.bind(interceptorManager);
  70. this.addResponseInterceptor =
  71. interceptorManager.addResponseInterceptor.bind(interceptorManager);
  72. // 实例化文件上传器
  73. const fileUploader = new FileUploader(this);
  74. this.upload = fileUploader.upload.bind(fileUploader);
  75. // 实例化文件下载器
  76. const fileDownloader = new FileDownloader(this);
  77. this.download = fileDownloader.download.bind(fileDownloader);
  78. // 实例化SSE模块
  79. const sse = new SSE(this);
  80. this.postSSE = sse.postSSE.bind(sse);
  81. this.requestSSE = sse.requestSSE.bind(sse);
  82. }
  83. /**
  84. * DELETE请求方法
  85. */
  86. public delete<T = any>(
  87. url: string,
  88. config?: RequestClientConfig,
  89. ): Promise<T> {
  90. return this.request<T>(url, { ...config, method: 'DELETE' });
  91. }
  92. /**
  93. * GET请求方法
  94. */
  95. public get<T = any>(url: string, config?: RequestClientConfig): Promise<T> {
  96. return this.request<T>(url, { ...config, method: 'GET' });
  97. }
  98. /**
  99. * 获取基础URL
  100. */
  101. public getBaseUrl() {
  102. return this.instance.defaults.baseURL;
  103. }
  104. /**
  105. * POST请求方法
  106. */
  107. public post<T = any>(
  108. url: string,
  109. data?: any,
  110. config?: RequestClientConfig,
  111. ): Promise<T> {
  112. return this.request<T>(url, { ...config, data, method: 'POST' });
  113. }
  114. /**
  115. * PUT请求方法
  116. */
  117. public put<T = any>(
  118. url: string,
  119. data?: any,
  120. config?: RequestClientConfig,
  121. ): Promise<T> {
  122. return this.request<T>(url, { ...config, data, method: 'PUT' });
  123. }
  124. /**
  125. * 通用的请求方法
  126. */
  127. public async request<T>(
  128. url: string,
  129. config: RequestClientConfig,
  130. ): Promise<T> {
  131. try {
  132. const response: AxiosResponse<T> = await this.instance({
  133. url,
  134. ...config,
  135. ...(config.paramsSerializer
  136. ? { paramsSerializer: getParamsSerializer(config.paramsSerializer) }
  137. : {}),
  138. });
  139. return response as T;
  140. } catch (error: any) {
  141. throw error.response ? error.response.data : error;
  142. }
  143. }
  144. }
  145. export { RequestClient };