JWT刷新令牌应该如何设计才能避免多次请求时的重复验证?
我在做文件上传功能时发现,当用户同时上传多个文件时,每个文件请求都会带着JWT访问接口,但遇到令牌过期的情况,所有请求都会触发刷新逻辑。比如这样:
axios.interceptors.response.use(
response => response,
error => {
if (error.response.status === 401 && !error.config.sentRefresh) {
return refreshToken().then(newToken => {
error.config.headers.Authorization = Bearer ${newToken};
error.config.sentRefresh = true;
return axios(error.config);
});
}
return Promise.reject(error);
}
);
虽然加了sentRefresh标记避免重复刷新,但实际测试时发现:当第一个请求触发刷新时,第二个请求可能在第一个刷新完成前也进入拦截器,导致重复发起刷新请求。有没有更好的方式让多个并发请求共享同一个刷新流程?
另外发现如果用户同时打开多个标签页上传文件,不同标签页的刷新请求会覆盖彼此的token,这样其他标签页的请求又会失效,这该怎么处理?
let isRefreshing = null;
let subscribers = [];
axios.interceptors.response.use(
response => response,
error => {
if (error.response.status === 401 && !error.config.sentRefresh) {
if (!isRefreshing) {
isRefreshing = refreshToken();
isRefreshing.then(() => {
subscribers.forEach(cb => cb());
subscribers = [];
isRefreshing = null;
});
}
error.config.sentRefresh = true;
return new Promise(resolve => {
subscribers.push(() => {
error.config.headers.Authorization =
Bearer ${localStorage.getItem('token')};resolve(axios(error.config));
});
});
}
return Promise.reject(error);
}
);
window.addEventListener('storage', e => {
if (e.key === 'token') {
localStorage.setItem('token', e.newValue);
}
});