| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- import type { SimpleAlovaOptions } from './types';
- import { useAppConfig } from '@vben/hooks';
- import { useAccessStore } from '@vben/stores';
- import { createServerTokenAuthentication } from 'alova/client';
- import JsonBigint from 'json-bigint';
- import { createAlovaClient } from './alova';
- /** 超出 JS 安全整数范围的 id 等字段在 JSON 解析时保留为字符串,避免精度丢失 */
- const parseJsonBody = JsonBigint({ storeAsString: true }).parse;
- const { requestBaseURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
- const BINARY_DOWNLOAD_CONTENT_TYPES = new Set([
- 'application/octet-stream',
- 'application/vnd.ms-excel',
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
- ]);
- function decodeContentDispositionFileName(value: string): string {
- try {
- return decodeURIComponent(value.trim());
- } catch {
- return value.trim();
- }
- }
- function parseContentDispositionFileName(
- disposition?: string | null,
- fallbackUrl?: string,
- ): string {
- if (disposition) {
- const utf8Match = disposition.match(/filename\*=UTF-8''([^;]+)/i);
- if (utf8Match?.[1]) {
- return decodeContentDispositionFileName(utf8Match[1]);
- }
- const fileNameMatch = disposition.match(/filename=["']?([^"';]+)["']?/i);
- if (fileNameMatch?.[1]) {
- return decodeContentDispositionFileName(fileNameMatch[1]);
- }
- }
- const urlFileName = fallbackUrl?.match(/[^/?#]+(?=$|[?#])/i)?.[0];
- return urlFileName ? decodeContentDispositionFileName(urlFileName) : 'download';
- }
- function isBinaryDownloadContentType(contentType?: string): boolean {
- if (!contentType) return false;
- return (
- BINARY_DOWNLOAD_CONTENT_TYPES.has(contentType) ||
- contentType.startsWith('application/vnd.openxmlformats-officedocument.')
- );
- }
- export default function createRequestClient(options?: SimpleAlovaOptions) {
- const store = options?.tokenStore ?? useAccessStore();
- const transform = options?.transform ?? ((body) => body);
- const interceptor = options?.interceptor ?? {
- async onSuccess(response, method) {
- if (response.status > 400) {
- const message = response.statusText;
- // eslint-disable-next-line no-throw-literal
- throw { message };
- }
- /* prettier-ignore */
- if (method.meta?.notParseResponse) return response.clone();
- /* prettier-ignore */
- const [contentType] = response.headers.get('content-type')?.split(';') ?? [];
- if (contentType === 'application/json') {
- const text = await response.text();
- const body = transform(text ? parseJsonBody(text) : {}, method);
- if (method.meta?.notParseResponseBody) return body;
- if (body.code === 0) return body.data;
- throw body;
- }
- if (isBinaryDownloadContentType(contentType)) {
- return {
- fileName: parseContentDispositionFileName(
- response.headers.get('content-disposition'),
- method.url,
- ),
- source: await response.blob(),
- };
- }
- return response;
- },
- };
- const instance = createAlovaClient({
- id: options?.id,
- baseURL:
- options?.baseURL ??
- requestBaseURL[options?.id?.toString().toLocaleLowerCase() ?? 'url'] ??
- requestBaseURL.url,
- tokenAuthentication: createServerTokenAuthentication({
- refreshTokenOnSuccess: {
- async isExpired(response) {
- return response.status === 401;
- },
- async handler(response) {
- if (store.refreshToken) {
- console.log(response);
- }
- },
- metaMatches: {
- authRole: 'refreshToken',
- refreshToken: true,
- },
- },
- login: {
- async handler(response, method) {
- const data = await interceptor.onSuccess?.(response.clone(), method);
- store.loginExpired = false;
- store.accessToken = data.accessToken;
- store.refreshToken = data.refreshToken;
- },
- metaMatches: {
- authRole: 'login',
- login: true,
- },
- },
- logout: {
- async handler() {
- store.loginExpired = true;
- store.accessToken = null;
- store.refreshToken = null;
- },
- metaMatches: {
- authRole: 'logout',
- logout: true,
- },
- },
- assignToken(method) {
- method.config.headers.Authorization ??= store.accessToken;
- },
- visitorMeta: {
- authRole: 'none',
- visitor: true,
- },
- }),
- cacheLogger: import.meta.env.DEV,
- });
- for (const [type, _interceptor] of Object.entries(interceptor)) {
- instance.interceptor(<any>type.slice(2).toLowerCase(), _interceptor);
- }
- return instance;
- }
- export * from './alova';
- export * from './composables';
- export * from './types';
- export * from 'alova/client';
|