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

相关推荐
阿乐今天敲代码没35 分钟前
echarts定制化柱状图——条纹柱状图
前端·echarts
linux-hzh41 分钟前
CSS回顾
前端·css
天若有情6731 小时前
C++ 结构体封装模式与 Promise 链式调用:设计思想的异曲同工
前端·javascript·c++
龙泉寺天下行走1 小时前
《进化陷阱》--AI 生成文章 《连载 1》
java·服务器·前端
HaanLen2 小时前
React19源码系列之渲染阶段performUnitOfWork
前端·javascript·react.js·react19源码
小徐敲java2 小时前
Vue3中reactive响应式使用注意事项
前端·javascript·vue.js
编码七号2 小时前
【知识点】关于vue3中markRow、shallowRef、shallowReactive的了解
前端·javascript·vue.js
劲爽小猴头3 小时前
HTML5快速入门-概览
前端·html·html5
酷爱码3 小时前
html5的响应式布局的方法示例详解
前端·html·html5
aiweker3 小时前
python web flask专题-Flask入门指南:从安装到核心功能详解
前端·python·flask