wip: 临时提交
This commit is contained in:
@@ -1,61 +1,183 @@
|
||||
import { getAccessToken, clearTokens } from "@/utils/auth";
|
||||
import { ApiCode } from "@/enums/api-code.enum";
|
||||
import { getAccessToken, getRefreshToken, isTokenExpired, setAccessToken } from "./auth";
|
||||
|
||||
export default function request<T>(options: UniApp.RequestOptions): Promise<T> {
|
||||
// H5 使用 VITE_APP_BASE_API 作为代理路径,其他平台使用 VITE_APP_API_URL 作为请求路径
|
||||
let baseApi = import.meta.env.VITE_APP_API_URL;
|
||||
// #ifdef H5
|
||||
baseApi = import.meta.env.VITE_APP_BASE_API;
|
||||
// #endif
|
||||
// 刷新令牌的锁,防止多个请求同时刷新令牌
|
||||
let isRefreshing = false;
|
||||
// 请求队列,存储需要等待令牌刷新的请求
|
||||
let refreshSubscribers: Array<(token: string) => void> = [];
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
...options,
|
||||
url: `${baseApi}${options.url}`,
|
||||
// 添加订阅者
|
||||
const subscribeTokenRefresh = (callback: (token: string) => void) => {
|
||||
refreshSubscribers.push(callback);
|
||||
};
|
||||
|
||||
// 执行所有订阅者
|
||||
const onRefreshed = (token: string) => {
|
||||
refreshSubscribers.forEach((callback) => callback(token));
|
||||
refreshSubscribers = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* 刷新令牌
|
||||
* @returns 新的访问令牌
|
||||
*/
|
||||
const refreshToken = async (): Promise<string> => {
|
||||
try {
|
||||
const refreshToken = getRefreshToken();
|
||||
if (!refreshToken) {
|
||||
throw new Error("刷新令牌不存在");
|
||||
}
|
||||
|
||||
const response = await uni.request({
|
||||
url: "/api/v1/auth/refresh-token",
|
||||
method: "POST",
|
||||
data: { refreshToken },
|
||||
header: {
|
||||
...options.header,
|
||||
Authorization: getAccessToken() ? `Bearer ${getAccessToken()}` : "",
|
||||
},
|
||||
success: (response) => {
|
||||
console.log("success response", response);
|
||||
const resData = response.data as ResponseData<T>;
|
||||
|
||||
// 业务状态码 00000 表示成功
|
||||
if (resData.code === ApiCode.SUCCESS) {
|
||||
resolve(resData.data);
|
||||
}
|
||||
// 令牌失效或过期处理
|
||||
else if (resData.code === ApiCode.TOKEN_INVALID) {
|
||||
console.log("令牌失效或过期处理");
|
||||
clearTokens();
|
||||
// 跳转到登录页
|
||||
uni.reLaunch({
|
||||
url: "/pages/login/index",
|
||||
});
|
||||
} else {
|
||||
// 其他业务处理失败
|
||||
uni.showToast({
|
||||
title: resData.msg || "业务处理失败",
|
||||
icon: "none",
|
||||
});
|
||||
reject({
|
||||
message: resData.msg || "业务处理失败",
|
||||
code: resData.code,
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.log("fail error", error);
|
||||
uni.showToast({
|
||||
title: "网络请求失败",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
reject({
|
||||
message: "网络请求失败",
|
||||
error,
|
||||
});
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const data = response.data as any;
|
||||
if (data.code !== 200 || !data.data.accessToken) {
|
||||
throw new Error("刷新令牌失败");
|
||||
}
|
||||
|
||||
const newToken = data.data.accessToken;
|
||||
setAccessToken(newToken);
|
||||
return newToken;
|
||||
} catch (error) {
|
||||
console.error("刷新令牌失败:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// 请求配置
|
||||
interface RequestOptions<T = any> {
|
||||
url: string;
|
||||
method: "GET" | "POST" | "PUT" | "DELETE";
|
||||
data?: T;
|
||||
header?: Record<string, string>;
|
||||
timeout?: number;
|
||||
responseType?: "text" | "arraybuffer";
|
||||
// 是否跳过令牌刷新 (用于刷新令牌接口本身)
|
||||
skipTokenRefresh?: boolean;
|
||||
}
|
||||
|
||||
// 请求函数
|
||||
function request<T = any>(options: RequestOptions): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
// 添加授权头
|
||||
const token = getAccessToken();
|
||||
const header = Object.assign({}, options.header || {});
|
||||
|
||||
if (token) {
|
||||
header["Authorization"] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
// 统一处理请求
|
||||
const handleRequest = () => {
|
||||
uni.request({
|
||||
url: options.url,
|
||||
method: options.method,
|
||||
data: options.data,
|
||||
header,
|
||||
timeout: options.timeout || 30000,
|
||||
responseType: options.responseType,
|
||||
success: (res: any) => {
|
||||
// 请求成功
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
resolve(res.data.data);
|
||||
}
|
||||
// 未授权错误
|
||||
else if (res.statusCode === 401) {
|
||||
// 跳过令牌刷新的请求直接返回错误
|
||||
if (options.skipTokenRefresh) {
|
||||
reject(new Error("未授权"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 尝试刷新令牌
|
||||
if (!isRefreshing) {
|
||||
isRefreshing = true;
|
||||
|
||||
refreshToken()
|
||||
.then((newToken) => {
|
||||
// 令牌刷新成功,通知所有等待的请求
|
||||
onRefreshed(newToken);
|
||||
// 重新发起请求
|
||||
header["Authorization"] = `Bearer ${newToken}`;
|
||||
handleRequest();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("令牌刷新失败:", err);
|
||||
// 刷新失败,清除订阅者
|
||||
refreshSubscribers = [];
|
||||
// 重定向到登录页
|
||||
uni.redirectTo({
|
||||
url: "/pages/login/index",
|
||||
});
|
||||
reject(err);
|
||||
})
|
||||
.finally(() => {
|
||||
isRefreshing = false;
|
||||
});
|
||||
} else {
|
||||
// 当前已有刷新令牌的请求,将此请求加入队列
|
||||
subscribeTokenRefresh((newToken) => {
|
||||
header["Authorization"] = `Bearer ${newToken}`;
|
||||
handleRequest();
|
||||
});
|
||||
}
|
||||
}
|
||||
// 其他错误
|
||||
else {
|
||||
const errorMsg = res.data.message || `请求失败: ${res.statusCode}`;
|
||||
reject(new Error(errorMsg));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(new Error(err.errMsg || "网络请求失败"));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 检查令牌是否过期
|
||||
if (token && !options.skipTokenRefresh && isTokenExpired(token)) {
|
||||
if (!isRefreshing) {
|
||||
isRefreshing = true;
|
||||
|
||||
refreshToken()
|
||||
.then((newToken) => {
|
||||
// 令牌刷新成功,通知所有等待的请求
|
||||
onRefreshed(newToken);
|
||||
// 重新发起请求
|
||||
header["Authorization"] = `Bearer ${newToken}`;
|
||||
handleRequest();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("令牌刷新失败:", err);
|
||||
// 刷新失败,清除订阅者
|
||||
refreshSubscribers = [];
|
||||
// 重定向到登录页
|
||||
uni.redirectTo({
|
||||
url: "/pages/login/index",
|
||||
});
|
||||
reject(err);
|
||||
})
|
||||
.finally(() => {
|
||||
isRefreshing = false;
|
||||
});
|
||||
} else {
|
||||
// 当前已有刷新令牌的请求,将此请求加入队列
|
||||
subscribeTokenRefresh((newToken) => {
|
||||
header["Authorization"] = `Bearer ${newToken}`;
|
||||
handleRequest();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 令牌有效或无需令牌,直接发起请求
|
||||
handleRequest();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default request;
|
||||
|
||||
Reference in New Issue
Block a user