feat(frontend): 401 redirect 回跳与启动期诊断输出

- 401 统一携带 redirect 跳登录,登录成功后回到原页面(防开放跳转校验)
- 并发 401 只清理会话并跳转一次
- 开发环境输出 [HTTP] 请求日志,新增 bootLog 启动横幅(API Base/Domain/Mode)
This commit is contained in:
Logan.Li committed 2026-09-14 15:27:54 +08:00
1 parent 373c1c359f
commit 1ac0a34717
5 files changed
+58 -7

No files matched your search

+26 -3
View File
@@ -19,6 +19,22 @@ export interface ListResponse<T = unknown> {
type Json = unknown;
// 并发 401 只清理会话并跳转一次,避免多个请求同时过期时重复登出/提示(借鉴 opsx-web-lite)。 // Logan.Li
let handling401 = false;
/** 401 统一处理:清理本地会话并携带 redirect 跳转登录页 // Logan.Li */
function handleUnauthorized(): void {
if (handling401) return;
handling401 = true;
clearToken();
useUserStore.getState().logout();
const current = window.location.pathname + window.location.search;
const target = current && current !== '/login'
? `/login?redirect=${encodeURIComponent(current)}`
: '/login';
window.location.href = target;
}
/** 统一 API 根路径,避免 get/post 与 download/upload 行为不一致 // Logan.Li */
export function getApiBase(): string {
const envBase = import.meta.env.VITE_API_BASE_URL;
@@ -93,16 +109,23 @@ async function request<T = any>(
headers.Authorization = 'Bearer ' + token;
}
if (import.meta.env.DEV) {
// 开发环境输出请求日志,便于排查 404/代理类问题(借鉴 opsx-web-lite) // Logan.Li
console.log(`[HTTP] ${method} ${url}`);
}
const response = await fetch(fullUrl, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
});
if (import.meta.env.DEV) {
console.log(`[HTTP] ${method} ${url} → HTTP ${response.status}`);
}
if (response.status === 401) {
clearToken();
useUserStore.getState().logout();
window.location.href = '/login';
handleUnauthorized();
throw new Error(i18n.t('common.requestts.sd3ab821c'));
}