This commit is contained in:
Putoo
2026-05-19 18:34:24 +08:00
parent 24c784e6a4
commit 2c85872abd
10 changed files with 341 additions and 61 deletions

View File

@@ -11,7 +11,9 @@ export type HandledRedirectError = {
export class ApiService {
private static initialized = false;
private static isRefreshing = false;
private static refreshWaiters: Array<(success: boolean) => void> = [];
private static get userStore() {
return useUserStore()
}
@@ -29,13 +31,57 @@ export class ApiService {
}
private static redirectToLogin() {
if (typeof localStorage !== "undefined") {
localStorage.removeItem("token");
localStorage.removeItem("userInfo");
this.userStore.offOnline();
window.location.href = "/";
}
private static waitForRefresh(): Promise<boolean> {
return new Promise(resolve => {
this.refreshWaiters.push(resolve);
});
}
private static notifyWaiters(success: boolean): void {
this.refreshWaiters.forEach(resolve => resolve(success));
this.refreshWaiters = [];
}
// 刷新 token支持并发排队多个请求同时 401 时只发一次刷新请求
private static async doRefreshToken(): Promise<boolean> {
if (this.isRefreshing) {
return this.waitForRefresh();
}
if (typeof window !== "undefined") {
PageExtend.Redirect("/home");
this.isRefreshing = true;
try {
const refToken = this.userStore.getRefToken;
const token = this.userStore.getToken
if (!refToken) {
this.notifyWaiters(false);
return false;
}
const result = await this.request.post<IResultData<{ token: string; refToken: string; userId: string }>>(
"/Login/RefreshToken",
{ refToken, token }
);
if (result.code === 0 && result.data) {
this.userStore.setToken(
result.data.userId,
result.data.token,
result.data.refToken ?? this.userStore.refToken
);
this.notifyWaiters(true);
return true;
}
this.notifyWaiters(false);
return false;
} catch {
this.notifyWaiters(false);
return false;
} finally {
this.isRefreshing = false;
}
}
@@ -66,30 +112,17 @@ export class ApiService {
return response;
}
const result = response.data;
if (result.code === 401) {
//401刷新token
console.log(result.data);
} else if (result.code === 40101) {
this.redirectToLogin();
if (result.code === 500) {
throw {
handled: true,
redirectTo: "/",//跳转回首页
message: result.msg || "登录已失效"
} satisfies HandledRedirectError;
} else if (result.code === 500) {
// 跳转错误页面
throw {
handled: true,
redirectTo: "/",//跳转回首页
message: result.msg || "登录已失效"
redirectTo: "/",
message: result.msg || "服务器内部错误"
} satisfies HandledRedirectError;
} else if (result.code === 404) {
// 跳转不存在页面
throw {
handled: true,
redirectTo: "/",//跳转回首页
message: result.msg || "登录已失效"
redirectTo: "/",
message: result.msg || "资源不存在"
} satisfies HandledRedirectError;
}
@@ -107,26 +140,57 @@ export class ApiService {
this.initialized = true;
}
private static executeRequest<T>(
method: HttpMethod,
url: string,
params: RequestParams
): Promise<IResultData<T>> {
switch (method) {
case "get":
return this.request.get<IResultData<T>>(url, { params });
case "post":
return this.request.post<IResultData<T>>(url, params);
case "put":
return this.request.put<IResultData<T>>(url, params);
case "delete":
return this.request.delete<IResultData<T>>(url, { params });
case "patch":
return this.request.patch<IResultData<T>>(url, params);
default:
throw new Error(`不支持的请求方法: ${method}`);
}
}
private static async requestWithRetry<T>(
method: HttpMethod,
url: string,
params: RequestParams,
isRetry: boolean
): Promise<IResultData<T>> {
const result = await this.executeRequest<T>(method, url, params);
if (result.code === 401 && !isRetry) {
const refreshed = await this.doRefreshToken();
if (refreshed) {
return this.requestWithRetry<T>(method, url, params, true);
}
this.redirectToLogin();
throw {
handled: true,
redirectTo: "/",
message: "登录已失效,请重新登录"
} satisfies HandledRedirectError;
}
return result;
}
public static async Request<T = any>(
method: HttpMethod,
url: string,
params: RequestParams = {}
): Promise<IResultData<T>> {
this.ensureInitialized();
switch (method) {
case "get":
return await this.request.get<IResultData<T>>(url, { params });
case "post":
return await this.request.post<IResultData<T>>(url, params);
case "put":
return await this.request.put<IResultData<T>>(url, params);
case "delete":
return await this.request.delete<IResultData<T>>(url, { params });
case "patch":
return await this.request.patch<IResultData<T>>(url, params);
default:
throw new Error(`不支持的请求方法: ${method}`);
}
return this.requestWithRetry<T>(method, url, params, false);
}
}