前端无感刷新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,又能保证用户体验的无感知,同时避免了不必要的性能开销。

相关推荐
一个懒人懒人5 分钟前
Promise async/await与fetch的概念
前端·javascript·html
Mintopia11 分钟前
Web 安全与反编译源码下的权限设计:构筑前后端一致的防护体系
前端·安全
输出输入13 分钟前
前端核心技术
开发语言·前端
Mintopia18 分钟前
Web 安全与反编译源码下的权限设计:构建前后端一体的信任防线
前端·安全·编译原理
林深现海38 分钟前
Jetson Orin nano/nx刷机后无法打开chrome/firefox浏览器
前端·chrome·firefox
黄诂多1 小时前
APP原生与H5互调Bridge技术原理及基础使用
前端
前端市界1 小时前
用 React 手搓一个 3D 翻页书籍组件,呼吸海浪式翻页,交互体验带感!
前端·架构·github
文艺理科生1 小时前
Nginx 路径映射深度解析:从本地开发到生产交付的底层哲学
前端·后端·架构
千寻girling1 小时前
主管:”人家 Node 框架都用 Nest.js 了 , 你怎么还在用 Express ?“
前端·后端·面试
C澒1 小时前
Vue 项目渐进式迁移 React:组件库接入与跨框架协同技术方案
前端·vue.js·react.js·架构·系统架构