admin-vben5/packages/effects/request/src/request-client/preset-interceptors.ts
Vben 0df8c5c02c
refactor: reconstruct language files into multi-file structures (#4683)
* refactor: reconstruct language files into multi-file structures

* chore: typo
2024-10-19 14:28:21 +08:00

127 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { RequestClient } from './request-client';
import type { MakeErrorMessageFn, ResponseInterceptorConfig } from './types';
import { $t } from '@vben/locales';
import axios from 'axios';
export const authenticateResponseInterceptor = ({
client,
doReAuthenticate,
doRefreshToken,
enableRefreshToken,
formatToken,
}: {
client: RequestClient;
doReAuthenticate: () => Promise<void>;
doRefreshToken: () => Promise<string>;
enableRefreshToken: boolean;
formatToken: (token: string) => null | string;
}): ResponseInterceptorConfig => {
return {
rejected: async (error) => {
const { config, response } = error;
// 如果不是 401 错误,直接抛出异常
if (response?.status !== 401) {
throw error;
}
// 判断是否启用了 refreshToken 功能
// 如果没有启用或者已经是重试请求了,直接跳转到重新登录
if (!enableRefreshToken || config.__isRetryRequest) {
await doReAuthenticate();
throw error;
}
// 如果正在刷新 token则将请求加入队列等待刷新完成
if (client.isRefreshing) {
return new Promise((resolve) => {
client.refreshTokenQueue.push((newToken: string) => {
config.headers.Authorization = formatToken(newToken);
resolve(client.request(config.url, { ...config }));
});
});
}
// 标记开始刷新 token
client.isRefreshing = true;
// 标记当前请求为重试请求,避免无限循环
config.__isRetryRequest = true;
try {
const newToken = await doRefreshToken();
// 处理队列中的请求
client.refreshTokenQueue.forEach((callback) => callback(newToken));
// 清空队列
client.refreshTokenQueue = [];
return client.request(error.config.url, { ...error.config });
} catch (refreshError) {
// 如果刷新 token 失败,处理错误(如强制登出或跳转登录页面)
client.refreshTokenQueue.forEach((callback) => callback(''));
client.refreshTokenQueue = [];
console.error('Refresh token failed, please login again.');
await doReAuthenticate();
throw refreshError;
} finally {
client.isRefreshing = false;
}
},
};
};
export const errorMessageResponseInterceptor = (
makeErrorMessage?: MakeErrorMessageFn,
): ResponseInterceptorConfig => {
return {
rejected: (error: any) => {
if (axios.isCancel(error)) {
return Promise.reject(error);
}
const err: string = error?.toString?.() ?? '';
let errMsg = '';
if (err?.includes('Network Error')) {
errMsg = $t('ui.fallback.http.networkError');
} else if (error?.message?.includes?.('timeout')) {
errMsg = $t('ui.fallback.http.requestTimeout');
}
if (errMsg) {
makeErrorMessage?.(errMsg, error);
return Promise.reject(error);
}
let errorMessage = '';
const status = error?.response?.status;
switch (status) {
case 400: {
errorMessage = $t('ui.fallback.http.badRequest');
break;
}
case 401: {
errorMessage = $t('ui.fallback.http.unauthorized');
break;
}
case 403: {
errorMessage = $t('ui.fallback.http.forbidden');
break;
}
case 404: {
errorMessage = $t('ui.fallback.http.notFound');
break;
}
case 408: {
errorMessage = $t('ui.fallback.http.requestTimeout');
break;
}
default: {
errorMessage = $t('ui.fallback.http.internalServerError');
}
}
makeErrorMessage?.(errorMessage, error);
return Promise.reject(error);
},
};
};