一、背景与核心需求
在前后端分离架构中,Token作为身份认证的核心凭证,其生命周期管理直接影响系统安全性与用户体验。传统Token机制存在两大痛点:
- 过期中断:用户操作过程中Token过期,导致请求失败,需手动重新登录。
- 体验割裂:显式跳转登录页或弹窗提示会打断用户操作流程。
无感刷新的核心目标是在Token即将过期时,自动完成续期并重试失败请求,使用户无感知地维持会话状态。alovajs作为轻量级前端框架,需通过拦截器、状态管理等技术实现这一机制。
二、无感刷新机制的核心原理
1. Token生命周期管理
- 双Token设计:
- Access Token:短期有效(如2小时),用于访问API。
- Refresh Token:长期有效(如7天),用于获取新的Access Token。
- 过期时间阈值:
设定提前续期的阈值(如剩余30分钟),避免请求因Token过期而失败。
2. 请求拦截与重试
- 拦截器逻辑:
在alovajs中通过封装axios或自定义请求库,拦截所有API请求。- 检查Access Token是否有效(剩余时间>阈值)。
- 若无效,使用Refresh Token获取新Token,并重试原请求。
- 错误分类处理:
- 401未授权:触发Token刷新流程。
- 403禁止访问:直接终止请求(非Token问题)。
- 网络错误:按重试策略处理。
三、alovajs中的实现步骤
1. 封装请求工具类
// src/utils/request.jsimport axios from 'axios';const service = axios.create({baseURL: 'https://api.example.com',timeout: 5000});// 请求拦截器service.interceptors.request.use((config) => {const token = localStorage.getItem('accessToken');if (token) {config.headers['Authorization'] = `Bearer ${token}`;}return config;},(error) => Promise.reject(error));// 响应拦截器service.interceptors.response.use((response) => response,async (error) => {const { response } = error;if (response?.status === 401) {try {const refreshToken = localStorage.getItem('refreshToken');const newToken = await refreshAccessToken(refreshToken); // 调用刷新接口localStorage.setItem('accessToken', newToken.accessToken);// 重试原请求return service(error.config);} catch (refreshError) {// 刷新失败,跳转登录window.location.href = '/login';return Promise.reject(refreshError);}}return Promise.reject(error);});async function refreshAccessToken(refreshToken) {const res = await axios.post('/auth/refresh', { refreshToken });return res.data;}export default service;
2. Token存储与过期检测
- 存储方案:
使用localStorage或sessionStorage存储Token,避免内存泄漏。 - 过期时间计算:
解析Token中的exp字段(Unix时间戳),计算剩余有效期。function isTokenExpired(token) {const payload = JSON.parse(atob(token.split('.')[1]));const expiresAt = payload.exp * 1000; // 转换为毫秒return Date.now() >= expiresAt;}
3. 自动刷新触发条件
- 前置检查:
在发起请求前,检查Access Token剩余时间是否小于阈值(如30分钟)。 - 静默刷新:
即使无请求,也可通过定时任务提前刷新Token(需权衡性能)。
四、优化策略与最佳实践
1. 并发请求处理
-
锁机制:
当多个请求同时触发Token刷新时,避免重复调用刷新接口。let isRefreshing = false;let subscribers = [];service.interceptors.response.use((response) => response,async (error) => {if (error.response?.status === 401) {if (!isRefreshing) {isRefreshing = true;const refreshToken = localStorage.getItem('refreshToken');try {const newToken = await refreshAccessToken(refreshToken);localStorage.setItem('accessToken', newToken.accessToken);subscribers.forEach((cb) => cb(newToken.accessToken));subscribers = [];} finally {isRefreshing = false;}}// 等待新Tokenreturn new Promise((resolve) => {subscribers.push((token) => {error.config.headers['Authorization'] = `Bearer ${token}`;resolve(service(error.config));});});}return Promise.reject(error);});
2. 安全性增强
- Refresh Token轮换:
每次刷新后生成新的Refresh Token,避免固定Token长期有效。 - HTTPS与CSRF防护:
确保刷新接口仅通过HTTPS访问,并添加CSRF Token。
3. 性能优化
- 缓存Token:
将Token解析后的payload缓存,减少重复解码开销。 - 请求合并:
对短时间内密集请求进行合并,减少刷新次数。
五、常见问题与解决方案
1. Refresh Token被盗用
- 解决方案:
- 设置Refresh Token的短期有效期(如1天)。
- 结合设备指纹或IP限制,检测异常刷新行为。
2. 移动端网络不稳定
- 解决方案:
- 增加重试次数(如最多3次)。
- 在无网络时缓存请求,待网络恢复后自动重试。
3. 多标签页同步
- 解决方案:
使用BroadcastChannel或localStorage事件监听,实现多标签页Token状态同步。
六、总结与展望
无感刷新机制通过自动化Token管理,显著提升了前端应用的流畅性与安全性。在alovajs中的实现需重点关注拦截器设计、并发控制及错误处理。未来可结合Service Worker实现离线场景下的请求缓存与重试,进一步优化用户体验。