index.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import type { SimpleAlovaOptions } from './types';
  2. import { useAppConfig } from '@vben/hooks';
  3. import { useAccessStore } from '@vben/stores';
  4. import { createServerTokenAuthentication } from 'alova/client';
  5. import { createAlovaClient } from './alova';
  6. const { requestBaseURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
  7. export default function createRequestClient(options?: SimpleAlovaOptions) {
  8. const store = options?.tokenStore ?? useAccessStore();
  9. const transform = options?.transform ?? ((body) => body);
  10. const interceptor = options?.interceptor ?? {
  11. async onSuccess(response, method) {
  12. if (response.status > 400) {
  13. const message = response.statusText;
  14. // eslint-disable-next-line no-throw-literal
  15. throw { message };
  16. }
  17. /* prettier-ignore */
  18. if (method.meta?.notParseResponse) return response.clone();
  19. /* prettier-ignore */
  20. const [contentType] = response.headers.get('content-type')?.split(';') ?? [];
  21. switch (contentType) {
  22. case 'application/json': {
  23. const body = transform(await response.json(), method);
  24. if (method.meta?.notParseResponseBody) return body;
  25. if (body.code === 0) return body.data;
  26. throw body;
  27. }
  28. case 'application/octet-stream': {
  29. /* prettier-ignore */
  30. const disposition = response.headers.get('content-disposition') ?? method.url;
  31. /* prettier-ignore */
  32. const fileName = disposition.match(/fileName=["']?([^"';]+)["']?/i)?.[1];
  33. return fileName
  34. ? {
  35. fileName: decodeURIComponent(fileName),
  36. source: await response.blob(),
  37. }
  38. : response;
  39. }
  40. default: {
  41. return response;
  42. }
  43. }
  44. },
  45. };
  46. const instance = createAlovaClient({
  47. id: options?.id,
  48. baseURL:
  49. options?.baseURL ??
  50. requestBaseURL[options?.id?.toString().toLocaleLowerCase() ?? 'url'] ??
  51. requestBaseURL.url,
  52. tokenAuthentication: createServerTokenAuthentication({
  53. refreshTokenOnSuccess: {
  54. async isExpired(response) {
  55. return response.status === 401;
  56. },
  57. async handler(response) {
  58. if (store.refreshToken) {
  59. console.log(response);
  60. }
  61. },
  62. metaMatches: {
  63. authRole: 'refreshToken',
  64. refreshToken: true,
  65. },
  66. },
  67. login: {
  68. async handler(response, method) {
  69. const data = await interceptor.onSuccess?.(response.clone(), method);
  70. store.loginExpired = false;
  71. store.accessToken = data.accessToken;
  72. store.refreshToken = data.refreshToken;
  73. },
  74. metaMatches: {
  75. authRole: 'login',
  76. login: true,
  77. },
  78. },
  79. logout: {
  80. async handler() {
  81. store.loginExpired = true;
  82. store.accessToken = null;
  83. store.refreshToken = null;
  84. },
  85. metaMatches: {
  86. authRole: 'logout',
  87. logout: true,
  88. },
  89. },
  90. assignToken(method) {
  91. method.config.headers.Authorization ??= store.accessToken;
  92. },
  93. visitorMeta: {
  94. authRole: 'none',
  95. visitor: true,
  96. },
  97. }),
  98. cacheLogger: import.meta.env.DEV,
  99. });
  100. for (const [type, _interceptor] of Object.entries(interceptor)) {
  101. instance.interceptor(<any>type.slice(2).toLowerCase(), _interceptor);
  102. }
  103. return instance;
  104. }
  105. export * from './alova';
  106. export * from './composables';
  107. export * from './types';
  108. export * from 'alova/client';