http.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
  2. import { ElMessage as Message, ElMessageBox as MessageBox, ElLoading as Loading } from 'element-plus';
  3. import tokenInfo from '@/stores/modules/token';
  4. import useUserInfo from "@/stores/modules/user";
  5. // 加载动画的并发管理
  6. const activeRequests = new Set<string>();
  7. let loadingObj = null;
  8. /**
  9. * 关闭加载动画
  10. * 当所有请求完成时,关闭加载动画
  11. */
  12. function loadingClose(requestId: string) {
  13. activeRequests.delete(requestId);
  14. if (activeRequests.size === 0 && loadingObj) {
  15. loadingObj.close();
  16. loadingObj = null
  17. }
  18. }
  19. /**
  20. * 创建一个axios实例,用于发送HTTP请求
  21. * 配置了请求拦截器和响应拦截器,支持加载动画和错误提示
  22. */
  23. const service = axios.create({
  24. timeout: 5000, // 设置请求超时时间
  25. baseURL: '__API__',
  26. });
  27. console.log('__API__');
  28. // 请求拦截器
  29. service.interceptors.request.use(
  30. (config: AxiosRequestConfig) => {
  31. // 在发送请求之前做些什么,例如添加 token
  32. const tokenInfoStore = tokenInfo();
  33. const token = tokenInfoStore.getToken; // 使用 getToken() 获取 token
  34. if (token) {
  35. config.headers['Authorization'] = `Bearer ${token}`;
  36. }
  37. // 如果配置中启用了加载动画,则显示加载动画
  38. if (config.loading) {
  39. const requestId = `${Date.now()}-${Math.random()}`;
  40. activeRequests.add(requestId);
  41. if (activeRequests.size === 1) {
  42. loadingObj = Loading.service({
  43. lock: true,
  44. text: '请稍候',
  45. background: 'rgba(0, 0, 0, 0)',
  46. });
  47. }
  48. config.requestId = requestId; // 将 requestId 挂载到 config 上
  49. }
  50. return config;
  51. },
  52. (error: AxiosError) => {
  53. // 对请求错误做些什么
  54. return Promise.reject(error);
  55. }
  56. );
  57. // 响应拦截器
  58. service.interceptors.response.use(
  59. (response: AxiosResponse) => {
  60. // 对响应数据做点什么
  61. const res = response.data;
  62. const useUserInfoStore = useUserInfo();
  63. // 如果配置中启用了加载动画,则关闭加载动画
  64. if (response.config?.loading && response.config.requestId) {
  65. loadingClose(response.config.requestId as string);
  66. }
  67. // 如果自定义状态码不为0,则判断为错误
  68. if (res.code !== 0) {
  69. switch (res.code) {
  70. case 401:
  71. Message({
  72. message: '登录状态已失效,请重新登录',
  73. type: 'error',
  74. duration: 3 * 1000,
  75. });
  76. useUserInfoStore.updateLoginShow(true)
  77. break;
  78. default:
  79. if (response.config.showErrorMessage) {
  80. if (res.message?.length > 30 || res.code === 400011) {
  81. let message = '<div style="white-space: pre-line; max-height: 500px; overflow: auto;">' + res.message + '</div>' || 'Error';
  82. MessageBox.alert(message, '提示', {
  83. dangerouslyUseHTMLString: true,
  84. });
  85. } else {
  86. Message({
  87. message: res.message || 'Error',
  88. type: 'error',
  89. duration: 5 * 1000,
  90. });
  91. }
  92. }
  93. break;
  94. }
  95. return Promise.reject(res || 'Error');
  96. } else {
  97. return res;
  98. }
  99. },
  100. (error: AxiosError) => {
  101. // 对响应错误做点什么
  102. let errMessage = '';
  103. // 如果配置中启用了加载动画,则关闭加载动画
  104. if (error.config?.loading && error.config.requestId) {
  105. loadingClose(error.config.requestId as string);
  106. }
  107. const useUserInfoStore = useUserInfo();
  108. try {
  109. if (error.response) {
  110. switch (error.response.status) {
  111. case 400: errMessage = '请求错误(400)'; break;
  112. case 401: errMessage = '登录状态已失效,请重新登录';
  113. useUserInfoStore.updateLoginShow(true)
  114. break;
  115. case 403: errMessage = '拒绝访问(403)'; break;
  116. case 404: errMessage = '请求出错(404)'; break;
  117. case 408: errMessage = '请求超时(408)'; break;
  118. case 500: errMessage = '服务器错误(500)'; break;
  119. case 501: errMessage = '服务未实现(501)'; break;
  120. case 502: errMessage = '网络错误(502)'; break;
  121. case 503: errMessage = '服务不可用(503)'; break;
  122. case 504: errMessage = '网络超时(504)'; break;
  123. case 505: errMessage = 'HTTP版本不受支持(505)'; break;
  124. default: errMessage = '连接出错!';
  125. }
  126. } else {
  127. errMessage = '未知错误';
  128. }
  129. } catch (e) {
  130. console.log(e);
  131. }
  132. // 如果配置中启用了错误提示,则显示错误信息
  133. if (error.config?.showErrorMessage) {
  134. if (error.message && error.message.includes('timeout')) {
  135. Message({
  136. message: '请求超时!',
  137. type: 'error',
  138. duration: 5 * 1000,
  139. });
  140. } else if (errMessage) {
  141. Message({
  142. message: errMessage,
  143. type: 'error',
  144. duration: 5 * 1000,
  145. });
  146. }
  147. }
  148. // 对响应错误做处理
  149. return Promise.reject(error);
  150. }
  151. );
  152. /**
  153. * 发起 GET 请求
  154. *
  155. * @template T 泛型,表示返回数据的类型
  156. * @param {string} url 请求的 URL
  157. * @param {any} [params] 请求参数
  158. * @returns {Promise<T>} 返回一个 Promise,解析为响应数据
  159. */
  160. export function GET<T>(url: string, data?: any,config): Promise<T> {
  161. return service.get(url, {
  162. params: data,
  163. loading: config?.loading ?? false,
  164. showErrorMessage: config?.showErrorMessage ?? true,
  165. });
  166. }
  167. /**
  168. * 发起 POST 请求
  169. *
  170. * @template T 泛型,表示返回数据的类型
  171. * @param {string} url 请求的 URL
  172. * @param {any} [data] 请求体
  173. * @param {any} [config] 请求配置
  174. * @returns {Promise<T>} 返回一个 Promise,解析为响应数据
  175. */
  176. export function POST<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
  177. return service.post(url, data, {
  178. ...config,
  179. loading: config?.loading ?? true,
  180. showErrorMessage: config?.showErrorMessage ?? true,
  181. });
  182. }
  183. // 导出配置好的 axios 实例
  184. export default service;