登陆优化
This commit is contained in:
@@ -57,6 +57,8 @@ const API_BASE = import.meta.env.VITE_API_BASE_URL || "";
|
||||
const TOKEN_KEY = "airshelf_token";
|
||||
const REMEMBER_KEY = "airshelf_remember"; // { username, expireAt } · 勾选「记住我 7 天」时写
|
||||
const REMEMBER_DAYS = 7;
|
||||
export const AUTH_INVALIDATED_EVENT = "airshelf:auth-invalidated";
|
||||
let authInvalidationNotified = false;
|
||||
const AUTH_MISSING_MESSAGES = new Set([
|
||||
"身份认证信息未提供。",
|
||||
"Authentication credentials were not provided."
|
||||
@@ -159,10 +161,17 @@ export function setToken(token: string | null, remember = true) {
|
||||
localStorage.removeItem(TOKEN_KEY);
|
||||
sessionStorage.removeItem(TOKEN_KEY);
|
||||
if (!token) return;
|
||||
authInvalidationNotified = false;
|
||||
if (remember) localStorage.setItem(TOKEN_KEY, token);
|
||||
else sessionStorage.setItem(TOKEN_KEY, token);
|
||||
}
|
||||
|
||||
function notifyAuthInvalidated() {
|
||||
if (authInvalidationNotified || typeof window === "undefined") return;
|
||||
authInvalidationNotified = true;
|
||||
window.dispatchEvent(new CustomEvent(AUTH_INVALIDATED_EVENT));
|
||||
}
|
||||
|
||||
async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
|
||||
const token = getToken();
|
||||
const headers = new Headers(options.headers);
|
||||
@@ -173,6 +182,9 @@ async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
|
||||
|
||||
const response = await fetch(`${API_BASE}${path}`, { ...options, headers });
|
||||
if (!response.ok) {
|
||||
// 已携带凭证却收到 401,说明 Token 已被服务端吊销。先通知应用壳弹出
|
||||
// 单设备登录提示,再保留原始错误给具体调用方处理。
|
||||
if (response.status === 401 && token && path !== "/api/auth/logout/") notifyAuthInvalidated();
|
||||
const text = await response.text();
|
||||
// DRF 错误体是 JSON({"detail": "..."} 或 {field: ["..."]}),提取人话给 toast,别把原始 JSON 怼到用户脸上
|
||||
let message = text || `${response.status} ${response.statusText}`;
|
||||
|
||||
Reference in New Issue
Block a user