news 2026/5/2 12:21:48

前端Token无感刷新:让用户像在游乐园畅玩一样流畅

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
前端Token无感刷新:让用户像在游乐园畅玩一样流畅

❤ 写在前面
如果觉得对你有帮助的话,点个小❤❤ 吧,你的支持是对我最大的鼓励~
个人独立开发wx小程序,感谢支持!


🎪 从游乐园门票说起

想象一下,你去游乐园玩,门票(Token)有一定有效期。传统方式中,门票过期时:

  • 保安拦下你:“票过期了,去售票处重新买!”
  • 你不得不离开项目,排队重新买票,再回来继续玩

无感刷新就像有个贴心助手:

  • 门票快过期时,助手悄悄帮你续期
  • 你完全感知不到,继续畅玩各个项目

这就是我们今天要实现的用户体验!

🔍 为什么需要Token刷新?

Token的生命周期

┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 登录获取 │────▶│ 使用Token │────▶│ Token过期 │ │ AccessToken │ │ 访问接口 │ │ 401错误 │ └─────────────┘ └─────────────┘ └─────────────┘ │ ┌─────────────────────┘ ▼ ┌─────────────┐ ┌─────────────┐ │ 传统方式: │────▶│ 用户需重新 │ │ 跳转登录页 │ │ 登录 │ └─────────────┘ └─────────────┘

问题来了:每次Token过期都让用户重新登录,体验极差!

🎯 无感刷新的核心思路

有效

已过期

用户发起请求

Token是否有效?

正常请求

拦截请求

是否正在刷新?

发起刷新请求

获取新Token

重试原请求

加入等待队列

刷新完成后重试

返回数据

💻 实战代码实现(基于axios)

第一步:基础配置

// tokenManager.jsclassTokenManager{constructor(){this.accessToken=localStorage.getItem('access_token');this.refreshToken=localStorage.getItem('refresh_token');this.isRefreshing=false;// 是否正在刷新this.requestsQueue=[];// 请求等待队列}// 保存tokensetTokens(accessToken,refreshToken){this.accessToken=accessToken;this.refreshToken=refreshToken;localStorage.setItem('access_token',accessToken);localStorage.setItem('refresh_token',refreshToken);}// 清除tokenclearTokens(){this.accessToken=null;this.refreshToken=null;localStorage.removeItem('access_token');localStorage.removeItem('refresh_token');}}

第二步:axios拦截器设置

// http.jsimportaxiosfrom'axios';importTokenManagerfrom'./tokenManager';consttokenManager=newTokenManager();consthttp=axios.create({baseURL:process.env.VUE_APP_BASE_API,timeout:10000});// 请求拦截器http.interceptors.request.use((config)=>{if(tokenManager.accessToken){config.headers.Authorization=`Bearer${tokenManager.accessToken}`;}returnconfig;},(error)=>{returnPromise.reject(error);});// 响应拦截器 - 核心逻辑在这里!http.interceptors.response.use((response)=>{// 正常响应直接返回returnresponse;},async(error)=>{constoriginalRequest=error.config;// 如果不是401错误,直接返回if(error.response?.status!==401||originalRequest._retry){returnPromise.reject(error);}// 标记这个请求已经重试过,避免无限循环originalRequest._retry=true;// 如果没有refreshToken,跳转到登录页if(!tokenManager.refreshToken){tokenManager.clearTokens();window.location.href='/login';returnPromise.reject(error);}// 如果正在刷新token,将请求加入队列if(tokenManager.isRefreshing){returnnewPromise((resolve)=>{tokenManager.requestsQueue.push(()=>{originalRequest.headers.Authorization=`Bearer${tokenManager.accessToken}`;resolve(http(originalRequest));});});}// 开始刷新tokentokenManager.isRefreshing=true;try{// 调用刷新接口const{data}=awaitaxios.post('/api/auth/refresh',{refresh_token:tokenManager.refreshToken});// 保存新tokentokenManager.setTokens(data.access_token,data.refresh_token);// 执行等待队列中的所有请求tokenManager.requestsQueue.forEach(callback=>callback());tokenManager.requestsQueue=[];// 重试原始请求originalRequest.headers.Authorization=`Bearer${data.access_token}`;returnhttp(originalRequest);}catch(refreshError){// 刷新失败,清除token并跳转登录tokenManager.clearTokens();tokenManager.requestsQueue=[];window.location.href='/login';returnPromise.reject(refreshError);}finally{tokenManager.isRefreshing=false;}});exportdefaulthttp;

第三步:使用示例

// userService.jsimporthttpfrom'./http';exportconstgetUserInfo=async()=>{try{constresponse=awaithttp.get('/api/user/info');returnresponse.data;}catch(error){console.error('获取用户信息失败:',error);throwerror;}};exportconstupdateProfile=async(data)=>{try{constresponse=awaithttp.post('/api/user/profile',data);returnresponse.data;}catch(error){console.error('更新资料失败:',error);throwerror;}};

🎨 增强体验:添加视觉提示

虽然说是"无感",但适当的提示能让体验更好:

// 在刷新token时显示加载提示letrefreshLoading=null;// 修改响应拦截器中的刷新部分try{// 显示轻量级提示refreshLoading=showLoading('正在更新登录状态...');const{data}=awaitaxios.post('/api/auth/refresh',{refresh_token:tokenManager.refreshToken});// 隐藏提示refreshLoading?.hide();showToast('登录状态已更新','success',2000);// ... 其余逻辑}catch(error){refreshLoading?.hide();showToast('登录已过期,请重新登录','error');// ... 其余错误处理}

🛡️ 安全注意事项

  1. Refresh Token有效期:通常比Access Token长,但也不是永久的
  2. 单次使用:每次使用Refresh Token后,服务端应该颁发新的Refresh Token
  3. 安全存储
    // 使用更安全的方式存储constsecureStorage={setItem:(key,value)=>{if(window.crypto&&window.crypto.subtle){// 考虑使用加密存储localStorage.setItem(key,value);}else{// 降级方案localStorage.setItem(key,value);}},getItem:(key)=>localStorage.getItem(key)};

🎪 回到游乐园比喻

现在我们的系统就像这样工作:

游乐园项目(API请求) → 检票口(拦截器) │ ├── 票有效 → 直接进入 │ ├── 票过期,有续票资格 → 助手悄悄续票 → 继续游玩 │ └── 票过期,无续票资格 → 引导重新购票(登录)

📊 性能优化小贴士

// 1. 预刷新:在token即将过期时提前刷新constshouldRefreshToken=()=>{consttokenExpiry=getTokenExpiry(tokenManager.accessToken);constnow=Date.now();// 在过期前5分钟开始刷新returntokenExpiry-now<5*60*1000;};// 2. 定时检查setInterval(()=>{if(shouldRefreshToken()&&!tokenManager.isRefreshing){refreshTokenSilently();}},60000);// 每分钟检查一次// 3. 并发控制优化constMAX_QUEUE_SIZE=50;if(tokenManager.requestsQueue.length>MAX_QUEUE_SIZE){// 队列过长,可能是异常情况tokenManager.requestsQueue=[];window.location.reload();// 或采取其他恢复措施}

🎉 总结

实现Token无感刷新的关键在于:

  1. 拦截401错误:在axios响应拦截器中捕获
  2. 避免并发刷新:用标志位和队列控制
  3. 优雅降级:刷新失败时友好引导重新登录
  4. 用户体验:适当的提示(但不是打断)

现在你的应用就像那个贴心的游乐园助手,让用户在不知不觉中保持登录状态,享受流畅的体验!

试试实现它,让你的应用告别烦人的"登录已过期"提示吧!🚀


小作业:你能想到在哪些场景下,即使实现了无感刷新,仍然需要主动提示用户重新登录吗?欢迎在评论区分享你的想法!💭

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 17:21:00

Pyfolio投资组合分析终极指南:量化投资实战手册

"为什么我的投资策略在回测时表现优异&#xff0c;实盘却屡屡亏损&#xff1f;"这可能是每个量化投资者最深的痛点。传统的Excel分析表早已无法应对海量交易数据的挑战&#xff0c;而复杂的代码编写又让非技术背景的投资者望而却步。 【免费下载链接】pyfolio Portfo…

作者头像 李华
网站建设 2026/5/2 6:33:37

QRemeshify完整指南:5分钟学会将三角网格转换为高质量四边形拓扑

你是否在为复杂的三角网格模型而烦恼&#xff1f;想要快速获得规整的四边形拓扑结构却不知从何下手&#xff1f;QRemeshify这款Blender重网格插件正是为你量身打造的终极解决方案。它能智能地将任意三角网格转换为高质量的四边形拓扑&#xff0c;让3D建模工作变得更加简单高效。…

作者头像 李华
网站建设 2026/5/1 4:49:07

小天才USB驱动下载与设备识别问题深度剖析

小天才USB连接为何总失败&#xff1f;从驱动签名到ADB枚举的硬核拆解 你有没有试过把小天才电话手表插上电脑&#xff0c;结果系统提示“未知设备”&#xff1f;明明只是想同步个联系人、升级下固件&#xff0c;却卡在“USB驱动下载”这一步动弹不得。重装驱动、换线、重启电脑…

作者头像 李华
网站建设 2026/5/1 7:36:45

Ventoy启动界面美化三步法:从单调到惊艳的实战手册

Ventoy启动界面美化三步法&#xff1a;从单调到惊艳的实战手册 【免费下载链接】Ventoy 一种新的可启动USB解决方案。 项目地址: https://gitcode.com/GitHub_Trending/ve/Ventoy 厌倦了千篇一律的启动界面&#xff1f;想要打造专属的个性化启动体验&#xff1f;Ventoy作…

作者头像 李华
网站建设 2026/4/29 13:04:23

Vue3+Element Plus后台管理系统:从零构建企业级应用的实战指南

Vue3Element Plus后台管理系统&#xff1a;从零构建企业级应用的实战指南 【免费下载链接】vue-element-plus-admin A backend management system based on vue3, typescript, element-plus, and vite 项目地址: https://gitcode.com/gh_mirrors/vu/vue-element-plus-admin …

作者头像 李华
网站建设 2026/5/1 14:23:44

终极指南:Windows Hyper-V运行macOS的完整配置方案

终极指南&#xff1a;Windows Hyper-V运行macOS的完整配置方案 【免费下载链接】OSX-Hyper-V OpenCore configuration for running macOS on Windows Hyper-V. 项目地址: https://gitcode.com/gh_mirrors/os/OSX-Hyper-V 想要在Windows电脑上无缝体验macOS系统吗&#x…

作者头像 李华