request.ts 3.7 KB

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