这是基于vue-vben-admin 模板适用于abp vNext的前端管理项目
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

124 lines
3.4 KiB

import type { RequestClient } from "./request-client";
import type { MakeErrorMessageFn, ResponseInterceptorConfig } from "./types";
import { t as $t } from "@/locales/i18n";
import axios from "axios";
export const authenticateResponseInterceptor = ({
client,
doReAuthenticate,
doRefreshToken,
enableRefreshToken,
formatToken,
}: {
client: RequestClient;
doReAuthenticate: () => Promise<void>;
enableRefreshToken: boolean;
doRefreshToken: () => Promise<string>;
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);
},
};
};