request.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /**
  2. * 该文件可自行根据业务逻辑进行调整
  3. */
  4. import { useAccessStore } from '@vben-core/stores';
  5. import { message } from 'ant-design-vue';
  6. import axios, {
  7. AxiosError,
  8. AxiosRequestConfig,
  9. AxiosResponse,
  10. InternalAxiosRequestConfig,
  11. } from 'axios';
  12. // 后端需要的 token 存放在header内的key字段
  13. // 可以根据自己的需要修改
  14. const REQUEST_HEADER_TOKEN_KEY = 'Authorization';
  15. type HttpConfig = InternalAxiosRequestConfig;
  16. interface HttpResponse<T = any> {
  17. code: number;
  18. message: string;
  19. result: T;
  20. }
  21. // 用于存储每个请求的标识和取消函数
  22. const pendingMap = new Map<string, AbortController>();
  23. const getPendingUrl = (config: AxiosRequestConfig): string => {
  24. return [config.method, config.url].join('&');
  25. };
  26. /**
  27. * 添加请求
  28. * @param config 请求配置
  29. */
  30. function addRequestSignal(config: AxiosRequestConfig): void {
  31. abortRequest(config);
  32. const url = getPendingUrl(config);
  33. const controller = new AbortController();
  34. config.signal = config.signal || controller.signal;
  35. if (!pendingMap.has(url)) {
  36. // 如果当前请求不在等待中,将其添加到等待中
  37. pendingMap.set(url, controller);
  38. }
  39. }
  40. /**
  41. * 清除所有等待中的请求
  42. */
  43. function abortAllRequest() {
  44. pendingMap.forEach((abortController) => {
  45. if (abortController) {
  46. abortController.abort();
  47. }
  48. });
  49. pendingMap.clear();
  50. }
  51. /**
  52. * 移除请求
  53. * @param config 请求配置
  54. */
  55. function abortRequest(config: AxiosRequestConfig): void {
  56. if (!config) {
  57. return;
  58. }
  59. const url = getPendingUrl(config);
  60. if (pendingMap.has(url)) {
  61. // 如果当前请求在等待中,取消它并将其从等待中移除
  62. const abortController = pendingMap.get(url);
  63. if (abortController) {
  64. abortController.abort(url);
  65. }
  66. pendingMap.delete(url);
  67. }
  68. }
  69. const axiosInstance = axios.create({
  70. // .env 环境获取请求地址
  71. baseURL: import.meta.env.VITE_GLOB_API_URL,
  72. headers: {
  73. 'Content-Type': 'application/json;charset=utf-8',
  74. },
  75. timeout: 10 * 1000,
  76. });
  77. // 请求拦截器
  78. axiosInstance.interceptors.request.use(
  79. (config: HttpConfig) => {
  80. addRequestSignal(config);
  81. // 携带 getAccessToken 在请求头
  82. const accessStore = useAccessStore();
  83. const getAccessToken = accessStore.getAccessToken;
  84. if (getAccessToken) {
  85. config.headers[REQUEST_HEADER_TOKEN_KEY] = getAccessToken;
  86. }
  87. return config;
  88. },
  89. (error: AxiosError) => {
  90. return Promise.reject(error);
  91. },
  92. );
  93. // 添加响应拦截器
  94. axiosInstance.interceptors.response.use(
  95. (response: AxiosResponse<HttpResponse>) => {
  96. const { data: responseData, status } = response;
  97. const { code, message: msg, result } = responseData;
  98. abortRequest(response.config);
  99. if (status === 200 && code === 0) {
  100. return result;
  101. } else {
  102. message.error(msg);
  103. throw new Error(msg);
  104. }
  105. },
  106. (error: any) => {
  107. if (axios.isCancel(error)) {
  108. return Promise.reject(error);
  109. }
  110. const err: string = error?.toString?.() ?? '';
  111. let errMsg = '';
  112. if (err?.includes('Network Error')) {
  113. errMsg = '网络错误。';
  114. } else if (error?.message?.includes?.('timeout')) {
  115. errMsg = '请求超时。';
  116. } else {
  117. errMsg = error?.response?.data?.error?.message ?? '';
  118. }
  119. message.error(errMsg);
  120. return Promise.reject(error);
  121. },
  122. );
  123. async function request<T>(url: string, config: AxiosRequestConfig): Promise<T> {
  124. try {
  125. const response: AxiosResponse<T> = await axiosInstance({
  126. url,
  127. ...config,
  128. });
  129. return response as T;
  130. } catch (error: any) {
  131. throw error.response ? error.response.data : error;
  132. }
  133. }
  134. export { abortAllRequest, request };