request.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /**
  2. * 该文件可自行根据业务逻辑进行调整
  3. */
  4. import type { RequestClientOptions } from '@vben/request';
  5. import { useAppConfig } from '@vben/hooks';
  6. import { preferences } from '@vben/preferences';
  7. import {
  8. authenticateResponseInterceptor,
  9. defaultResponseInterceptor,
  10. errorMessageResponseInterceptor,
  11. RequestClient,
  12. } from '@vben/request';
  13. import { useAccessStore } from '@vben/stores';
  14. import { message } from 'ant-design-vue';
  15. import { useAuthStore } from '#/store';
  16. import { refreshTokenApi } from './core';
  17. const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
  18. function createRequestClient(baseURL: string, options?: RequestClientOptions) {
  19. const client = new RequestClient({
  20. ...options,
  21. baseURL,
  22. });
  23. /**
  24. * 重新认证逻辑
  25. */
  26. async function doReAuthenticate() {
  27. console.warn('Access token or refresh token is invalid or expired. ');
  28. const accessStore = useAccessStore();
  29. const authStore = useAuthStore();
  30. accessStore.setAccessToken(null);
  31. if (
  32. preferences.app.loginExpiredMode === 'modal' &&
  33. accessStore.isAccessChecked
  34. ) {
  35. accessStore.setLoginExpired(true);
  36. } else {
  37. await authStore.logout();
  38. }
  39. }
  40. /**
  41. * 刷新token逻辑
  42. */
  43. async function doRefreshToken() {
  44. const accessStore = useAccessStore();
  45. const resp = await refreshTokenApi();
  46. const newToken = resp.data;
  47. accessStore.setAccessToken(newToken);
  48. return newToken;
  49. }
  50. function formatToken(token: null | string) {
  51. return token ? `Bearer ${token}` : null;
  52. }
  53. // 请求头处理
  54. client.addRequestInterceptor({
  55. fulfilled: async (config) => {
  56. const accessStore = useAccessStore();
  57. config.headers.Authorization = formatToken(accessStore.accessToken);
  58. config.headers['Accept-Language'] = preferences.app.locale;
  59. return config;
  60. },
  61. });
  62. // 处理返回的响应数据格式
  63. client.addResponseInterceptor(
  64. defaultResponseInterceptor({
  65. codeField: 'code',
  66. dataField: 'data',
  67. successCode: 0,
  68. }),
  69. );
  70. // token过期的处理
  71. client.addResponseInterceptor(
  72. authenticateResponseInterceptor({
  73. client,
  74. doReAuthenticate,
  75. doRefreshToken,
  76. enableRefreshToken: preferences.app.enableRefreshToken,
  77. formatToken,
  78. }),
  79. );
  80. // 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
  81. client.addResponseInterceptor(
  82. errorMessageResponseInterceptor((msg: string, error) => {
  83. // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
  84. // 当前mock接口返回的错误字段是 error 或者 message
  85. const responseData = error?.response?.data ?? {};
  86. const errorMessage = responseData?.error ?? responseData?.message ?? '';
  87. // 如果没有错误信息,则会根据状态码进行提示
  88. message.error(errorMessage || msg);
  89. }),
  90. );
  91. return client;
  92. }
  93. export const requestClient = createRequestClient(apiURL, {
  94. responseReturn: 'data',
  95. });
  96. export const baseRequestClient = new RequestClient({ baseURL: apiURL });