刷新token

This commit is contained in:
马梓彭 2026-04-03 17:49:06 +08:00
parent 2bd38e627a
commit 54bc72002c

View File

@ -14,6 +14,10 @@ export const clearAccessTokens = () => {
Session.remove(refreshAccessTokenKey); Session.remove(refreshAccessTokenKey);
}; };
// Token刷新状态和请求队列
let isRefreshing = false;
let requestQueue: Array<(token: string) => void> = [];
/** /**
* 检查并存储授权信息 * 检查并存储授权信息
* @param res 响应对象 * @param res 响应对象
@ -97,6 +101,15 @@ class Axios {
async (res: AxiosResponse) => { async (res: AxiosResponse) => {
// 检查并存储授权信息 // 检查并存储授权信息
checkAndStoreAuthentication(res); checkAndStoreAuthentication(res);
// 如果正在刷新Token,且响应中包含新Token,说明刷新成功
if (isRefreshing && res.headers[accessTokenKey]) {
const newToken = res.headers[accessTokenKey];
isRefreshing = false;
requestQueue.forEach((callback) => callback(newToken));
requestQueue = [];
}
const data = res.data; const data = res.data;
if (res.config.url?.toLocaleLowerCase() === '/file/upload'.toLowerCase()) { if (res.config.url?.toLocaleLowerCase() === '/file/upload'.toLowerCase()) {
return data; return data;
@ -111,10 +124,6 @@ class Axios {
case 401: case 401:
clearAccessTokens(); clearAccessTokens();
message = '您已登出,请重新登录'; message = '您已登出,请重新登录';
// ElMessageBox.alert('您已登出,请重新登录', '提示', {})
// .then(() => {})
// .catch(() => {});
// window.location.href = '/'; // 去登录页
break; break;
case 403: case 403:
message = '您没有权限,无法执行此项操作!'; message = '您没有权限,无法执行此项操作!';
@ -130,11 +139,54 @@ class Axios {
}); });
if (data.statusCode === 401) { if (data.statusCode === 401) {
clearAccessTokens(); clearAccessTokens();
isRefreshing = false;
requestQueue = [];
window.location.href = '/'; // 去登录页 window.location.href = '/'; // 去登录页
} }
return Promise.reject(new Error(data.errors || 'Error')); return Promise.reject(new Error(data.errors || 'Error'));
}, },
(err: any) => { async (err: any) => {
const originalRequest = err.config;
// 如果是401错误且不是重试请求
if (err.response && err.response.status === 401 && !originalRequest._retry) {
// 如果已经在刷新Token,将请求加入队列
if (isRefreshing) {
return new Promise((resolve) => {
requestQueue.push((newToken: string) => {
originalRequest.headers['Authorization'] = `Bearer ${newToken}`;
resolve(this.instance(originalRequest));
});
});
}
// 开始刷新Token
originalRequest._retry = true;
isRefreshing = true;
// 检查是否有刷新Token
const refreshAccessToken = Session.get<string>(refreshAccessTokenKey);
if (!refreshAccessToken) {
clearAccessTokens();
isRefreshing = false;
window.location.href = '/';
return Promise.reject(err);
}
try {
// 重新发送原请求,Furion会自动处理Token刷新
originalRequest.headers['X-Authorization'] = `Bearer ${refreshAccessToken}`;
return this.instance(originalRequest);
} catch (refreshErr) {
// 刷新失败,清除所有Token并跳转登录页
clearAccessTokens();
isRefreshing = false;
requestQueue = [];
window.location.href = '/';
return Promise.reject(refreshErr);
}
}
// 这里用来处理http常见错误,进行全局提示 // 这里用来处理http常见错误,进行全局提示
let message = err.message; let message = err.message;
if (err.response && err.response.status) { if (err.response && err.response.status) {
@ -144,7 +196,8 @@ class Axios {
break; break;
case 401: case 401:
message = '未授权,请重新登录(401)'; message = '未授权,请重新登录(401)';
// 这里可以做清空storage并跳转到登录页的操作 clearAccessTokens();
window.location.href = '/';
break; break;
case 403: case 403:
message = '拒绝访问(403)'; message = '拒绝访问(403)';
@ -179,7 +232,6 @@ class Axios {
} }
// 这里错误消息可以使用全局弹框展示出来 // 这里错误消息可以使用全局弹框展示出来
if (message) { if (message) {
// 比如element plus 可以使用 ElMessage
ElMessage({ ElMessage({
showClose: true, showClose: true,
message: `${message},请检查网络或联系管理员!`, message: `${message},请检查网络或联系管理员!`,