JWT刷新令牌应该如何设计才能避免多次请求时的重复验证?

程序猿淑芳 阅读 37

我在做文件上传功能时发现,当用户同时上传多个文件时,每个文件请求都会带着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,这样其他标签页的请求又会失效,这该怎么处理?

我来解答 赞 7 收藏
二维码
手机扫码查看
1 条解答
梓熙的笔记
用一个 Promise 变量挂起刷新过程,所有并发请求都等待这个 Promise 完成。localStorage 监听解决多标签覆盖问题,改成这样:

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);
}
});
点赞 7
2026-02-06 14:04