Node.js Express:如何在不中断请求的情况下刷新访问令牌?
无中断刷新JWT令牌的优化方案
现有方案的快速优化
- 页面初始化主动校验:用户打开/返回网站时,优先执行token校验逻辑:
- 读取cookie中的accessToken,解析其过期时间(或从localStorage读取预存的过期时间戳)
- 若accessToken已过期,立即携带refreshToken调用
/refresh接口刷新令牌 - 刷新成功后更新cookie中的accessToken和本地存储的过期时间,再加载页面内容;若刷新失败再跳转登录页
- 替换轮询为延迟触发:取消每秒轮询的冗余逻辑,登录成功后计算accessToken过期前5分钟的时间点,用
setTimeout设置单次刷新触发,刷新成功后再重置延迟定时器,减少性能消耗。
无中断请求的核心方案(拦截请求自动处理)
用请求拦截器实现令牌失效的无缝处理,彻底避免用户感知:
- 请求前拦截:在发送业务请求前,检查accessToken是否即将过期(比如剩余时间小于1分钟),若已过期则先调用
/refresh刷新令牌,拿到新token后再发送原请求 - 响应拦截处理401:若请求返回401(accessToken失效),执行以下逻辑:
- 检查是否存在有效的refreshToken
- 若存在,调用
/refresh接口获取新的accessToken - 用新token重试原请求,成功则返回结果,失败再跳转登录页
- 并发请求控制:设置全局状态标记是否正在刷新令牌,当多个请求同时触发401时,只发起一次刷新请求,其余请求等待刷新完成后统一重试,避免重复调用
/refresh接口。
伪代码示例(Axios拦截器)
let isRefreshing = false; let requestQueue = []; // 请求拦截器 axios.interceptors.request.use(config => { const accessToken = getCookie('accessToken'); const expiresAt = localStorage.getItem('expiresAt'); // 检查token是否即将过期 if (Date.now() > expiresAt - 60 * 1000) { return refreshToken().then(newToken => { config.headers['Authorization'] = `Bearer ${newToken}`; return config; }); } config.headers['Authorization'] = `Bearer ${accessToken}`; return config; }); // 响应拦截器 axios.interceptors.response.use(response => response, error => { const { config, response } = error; if (response?.status === 401) { if (!isRefreshing) { isRefreshing = true; // 调用刷新接口 refreshToken().then(newToken => { isRefreshing = false; // 更新token setCookie('accessToken', newToken); localStorage.setItem('expiresAt', new Date().getTime() + 15 * 60 * 1000); // 重试队列中的请求 requestQueue.forEach(cb => cb(newToken)); requestQueue = []; }).catch(() => { isRefreshing = false; // 刷新失败跳转登录 window.location.href = '/login'; }); } // 将当前请求加入队列,等待刷新完成 return new Promise(resolve => { requestQueue.push(token => { config.headers['Authorization'] = `Bearer ${token}`; resolve(axios(config)); }); }); } return Promise.reject(error); }); function refreshToken() { const refreshToken = localStorage.getItem('refreshToken'); return axios.post('/refresh', { refreshToken }).then(res => res.data.accessToken); }
存储安全性优化
将refreshToken存储到HttpOnly、Secure、SameSite=Strict的cookie中,前端无需手动携带,服务器在处理/refresh请求时直接从cookie读取,避免XSS攻击风险,同时简化前端逻辑。
内容的提问来源于stack exchange,提问作者Aran Bins
相关产品推荐
相关产品推荐

