request-client.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import type {
  2. AxiosInstance,
  3. AxiosRequestConfig,
  4. AxiosResponse,
  5. CreateAxiosDefaults,
  6. } from 'axios';
  7. import { merge } from '@vben/utils';
  8. import axios from 'axios';
  9. import { FileDownloader } from './modules/downloader';
  10. import { InterceptorManager } from './modules/interceptor';
  11. import { FileUploader } from './modules/uploader';
  12. import { type RequestClientOptions } from './types';
  13. class RequestClient {
  14. private readonly instance: AxiosInstance;
  15. public addRequestInterceptor: InterceptorManager['addRequestInterceptor'];
  16. public addResponseInterceptor: InterceptorManager['addResponseInterceptor'];
  17. public download: FileDownloader['download'];
  18. // 是否正在刷新token
  19. public isRefreshing = false;
  20. // 刷新token队列
  21. public refreshTokenQueue: ((token: string) => void)[] = [];
  22. public upload: FileUploader['upload'];
  23. /**
  24. * 构造函数,用于创建Axios实例
  25. * @param options - Axios请求配置,可选
  26. */
  27. constructor(options: RequestClientOptions = {}) {
  28. // 合并默认配置和传入的配置
  29. const defaultConfig: CreateAxiosDefaults = {
  30. headers: {
  31. 'Content-Type': 'application/json;charset=utf-8',
  32. },
  33. // 默认超时时间
  34. timeout: 10_000,
  35. };
  36. const { ...axiosConfig } = options;
  37. const requestConfig = merge(axiosConfig, defaultConfig);
  38. this.instance = axios.create(requestConfig);
  39. this.bindMethods();
  40. // 实例化拦截器管理器
  41. const interceptorManager = new InterceptorManager(this.instance);
  42. this.addRequestInterceptor =
  43. interceptorManager.addRequestInterceptor.bind(interceptorManager);
  44. this.addResponseInterceptor =
  45. interceptorManager.addResponseInterceptor.bind(interceptorManager);
  46. // 实例化文件上传器
  47. const fileUploader = new FileUploader(this);
  48. this.upload = fileUploader.upload.bind(fileUploader);
  49. // 实例化文件下载器
  50. const fileDownloader = new FileDownloader(this);
  51. this.download = fileDownloader.download.bind(fileDownloader);
  52. }
  53. private bindMethods() {
  54. const propertyNames = Object.getOwnPropertyNames(
  55. Object.getPrototypeOf(this),
  56. );
  57. propertyNames.forEach((propertyName) => {
  58. const propertyValue = (this as any)[propertyName];
  59. if (
  60. typeof propertyValue === 'function' &&
  61. propertyName !== 'constructor'
  62. ) {
  63. (this as any)[propertyName] = propertyValue.bind(this);
  64. }
  65. });
  66. }
  67. /**
  68. * DELETE请求方法
  69. */
  70. public delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
  71. return this.request<T>(url, { ...config, method: 'DELETE' });
  72. }
  73. /**
  74. * GET请求方法
  75. */
  76. public get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
  77. return this.request<T>(url, { ...config, method: 'GET' });
  78. }
  79. /**
  80. * POST请求方法
  81. */
  82. public post<T = any>(
  83. url: string,
  84. data?: any,
  85. config?: AxiosRequestConfig,
  86. ): Promise<T> {
  87. return this.request<T>(url, { ...config, data, method: 'POST' });
  88. }
  89. /**
  90. * PUT请求方法
  91. */
  92. public put<T = any>(
  93. url: string,
  94. data?: any,
  95. config?: AxiosRequestConfig,
  96. ): Promise<T> {
  97. return this.request<T>(url, { ...config, data, method: 'PUT' });
  98. }
  99. /**
  100. * 通用的请求方法
  101. */
  102. public async request<T>(url: string, config: AxiosRequestConfig): Promise<T> {
  103. try {
  104. const response: AxiosResponse<T> = await this.instance({
  105. url,
  106. ...config,
  107. });
  108. return response as T;
  109. } catch (error: any) {
  110. throw error.response ? error.response.data : error;
  111. }
  112. }
  113. }
  114. export { RequestClient };