前端无感刷新Token实现(基于Axios)

前端添加防抖/节流机制的无感刷新Token实现(基于Axios)

为了防止在短时间内多次触发token刷新,我们可以添加防抖(debounce)或节流(throttle)机制。下面是优化后的代码:

  1. 工具函数(防抖和节流)
javascript 复制代码
// 防抖函数
function debounce(fn, delay) {
  let timer = null;
  return function(...args) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

// 节流函数
function throttle(fn, delay) {
  let lastTime = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastTime >= delay) {
      fn.apply(this, args);
      lastTime = now;
    }
  };
}
  1. 优化后的刷新Token逻辑
javascript 复制代码
let isRefreshing = false;
let requests = [];
// 添加节流时间(例如5秒内不重复刷新)
const REFRESH_THROTTLE_TIME = 5000; 
let lastRefreshTime = 0;

// 带节流的刷新token函数
const refreshTokenWithThrottle = throttle(async () => {
  try {
    const refreshToken = localStorage.getItem('refresh_token');
    if (!refreshToken) {
      throw new Error('No refresh token available');
    }
    
    const res = await axios.post('/auth/refreshToken', { refreshToken });
    const { access_token, refresh_token } = res.data;
    
    localStorage.setItem('access_token', access_token);
    localStorage.setItem('refresh_token', refresh_token);
    
    return access_token;
  } catch (error) {
    // 清除token并跳转登录
    localStorage.removeItem('access_token');
    localStorage.removeItem('refresh_token');
    window.location.href = '/login';
    throw error;
  }
}, REFRESH_THROTTLE_TIME);

// 带防抖的请求重试函数
const retryRequests = debounce(() => {
  requests.forEach(cb => cb());
  requests = [];
}, 100);
3. 优化后的响应拦截器
javascript
service.interceptors.response.use(
  response => response.data,
  async error => {
    const { config, response } = error;
    
    if (!response || response.status !== 401) {
      return Promise.reject(error);
    }
    
    if (config.url.includes('/refreshToken')) {
      window.location.href = '/login';
      return Promise.reject(error);
    }
    
    // 检查是否在节流时间内
    const now = Date.now();
    if (isRefreshing && now - lastRefreshTime < REFRESH_THROTTLE_TIME) {
      return new Promise(resolve => {
        requests.push(() => resolve(service(config)));
      });
    }
    
    isRefreshing = true;
    lastRefreshTime = now;
    
    try {
      const newToken = await refreshTokenWithThrottle();
      
      // 更新当前请求的header
      if (config.headers) {
        config.headers['Authorization'] = `Bearer ${newToken}`;
      }
      
      // 防抖执行重试
      retryRequests();
      
      return service(config);
    } catch (refreshError) {
      return Promise.reject(refreshError);
    } finally {
      isRefreshing = false;
    }
  }
);
  1. 完整优化点说明
    节流刷新Token:设置了REFRESH_THROTTLE_TIME(如5秒)
    在节流时间内不会重复刷新token,避免短时间内因多个接口401导致多次刷新

防抖重试请求:使用防抖技术合并短时间内多个重试请求,减少不必要的重复请求

时间戳控制:记录最后一次刷新时间lastRefreshTime,精确控制节流间隔

错误处理优化:统一处理刷新失败的情况,确保最终会跳转登录页

  1. 配置建议
javascript 复制代码
// 可以根据实际需求调整这些参数
const CONFIG = {
  refreshThrottleTime: 5000, // 5秒内不重复刷新
  retryDebounceTime: 100,    // 100ms内合并重试请求
  maxRetryTimes: 3,          // 最大重试次数(可选)
};
  1. 额外优化建议
    添加最大重试次数限制:
javascript 复制代码
let retryCount = 0;
const MAX_RETRY_TIMES = 3;

// 在刷新token前检查
if (retryCount >= MAX_RETRY_TIMES) {
  localStorage.removeItem('access_token');
  localStorage.removeItem('refresh_token');
  window.location.href = '/login';
  return Promise.reject(new Error('Max retry times exceeded'));
}

网络状态检测:

javascript 复制代码
// 可以在刷新前检查网络状态
if (!navigator.onLine) {
  return Promise.reject(new Error('Network unavailable'));
}

Token过期预判:

javascript 复制代码
// 可以在请求前判断token是否即将过期
function isTokenExpiringSoon(token) {
  // 解析token的exp字段
  // 如果剩余时间小于某个阈值(如5分钟),返回true
}

这种实现方式既防止了频繁刷新token,又能保证用户体验的无感知,同时避免了不必要的性能开销。

相关推荐
阳火锅19 分钟前
Element / AntD 官方都没做好的功能,被这个开源小插件搞定了!
前端·vue.js·面试
大阳光男孩19 分钟前
Uniapp+Vue3树形选择器
前端·javascript·uni-app
沙振宇25 分钟前
【Web】使用Vue3+PlayCanvas开发3D游戏(九)纹理视觉效果
前端·游戏·3d·纹理
前端 贾公子26 分钟前
uniapp中@input修改input内容不生效 | 过滤赋值无效 | 连续非法字符不更新的问题
开发语言·前端·javascript
写不来代码的草莓熊30 分钟前
el-date-picker ,自定义输入数字自动转换显示yyyy-mm-dd HH:mm:ss格式 【仅双日历 datetimerange专用】
开发语言·前端·javascript
绺年30 分钟前
关于 mac 使用ssh配置
前端
LDX前端校草31 分钟前
verdaccio数据迁移
前端
炸炸鱼.1 小时前
LVS-DR 群集部署
前端·chrome·lvs
Ava的硅谷新视界1 小时前
TypeScript 中用判别联合类型替代 instanceof 检查
前端·javascript·typescript
ZC跨境爬虫1 小时前
海南大学交友平台开发实战 day9(头像上传存入 SQLite+BLOB 存储 + 前后端联调避坑全记录)
前端·数据库·python·sqlite