You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js Express:如何在不中断请求的情况下刷新访问令牌?

无中断刷新JWT令牌的优化方案

现有方案的快速优化

  • 页面初始化主动校验:用户打开/返回网站时,优先执行token校验逻辑:
    1. 读取cookie中的accessToken,解析其过期时间(或从localStorage读取预存的过期时间戳)
    2. 若accessToken已过期,立即携带refreshToken调用/refresh接口刷新令牌
    3. 刷新成功后更新cookie中的accessToken和本地存储的过期时间,再加载页面内容;若刷新失败再跳转登录页
  • 替换轮询为延迟触发:取消每秒轮询的冗余逻辑,登录成功后计算accessToken过期前5分钟的时间点,用setTimeout设置单次刷新触发,刷新成功后再重置延迟定时器,减少性能消耗。

无中断请求的核心方案(拦截请求自动处理)

用请求拦截器实现令牌失效的无缝处理,彻底避免用户感知:

  1. 请求前拦截:在发送业务请求前,检查accessToken是否即将过期(比如剩余时间小于1分钟),若已过期则先调用/refresh刷新令牌,拿到新token后再发送原请求
  2. 响应拦截处理401:若请求返回401(accessToken失效),执行以下逻辑:
    • 检查是否存在有效的refreshToken
    • 若存在,调用/refresh接口获取新的accessToken
    • 用新token重试原请求,成功则返回结果,失败再跳转登录页
  3. 并发请求控制:设置全局状态标记是否正在刷新令牌,当多个请求同时触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 00:22:31