全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2023-12-26_项目中前端如何实现无感刷新 token!

您的位置:首页 >> 新闻 >> 行业资讯

项目中前端如何实现无感刷新 token! 点击关注公众号回复”小册” 优惠券免费领!!前一阵遇到了一个问题,线上平台有时会出现用户正在使用的时候,突然要用户去进行登录,这样会造成很不好的用户体验,但是当时一直没有好的思路因此搁置了下来;通过零散时间查询资料以及思考,最终解决了这个问题,接下来跟大家分享一下! 环境请求采用的 Axios V1.3.2。平台的采用的 JWT(JSON Web Tokens) 进行用户登录鉴权。 「(拓展:JWT 是一种认证机制,让后台知道该请求是来自于受信的客户端;更详细的可以自行查询相关资料)」问题现象线上用户在使用的时候,偶尔会出现突然跳转到登录页面,需要重新登录的现象。 原因突然跳转到登录页面,是由于当前的 token 过期,导致请求失败;在 axios 的响应拦截axiosInstance.interceptors.response.use中处理失败请求返回的状态码 401,此时得知token失效,因此跳转到登录页面,让用户重新进行登录。平台目前的逻辑是在 token 未过期内,用户登录平台可直接进入首页,无需进行登录操作;因此就存在该现象:用户打开平台,由于此时 token 未过期,用户直接进入到了首页,进行其他操作。但是在用户操作的过程中,token 突然失效了,此时就会出现突然跳转到登录页面,严重影响用户的体验感! (「注:目前线上项目中存在数据大屏,一些实时数据的显示;因此存在用户长时间停留在大屏页面,不进行操作,查看实时数据的情况」)切入点怎样及时的、在用户感知不到的情况下更新token?当 token 失效的情况下,出错的请求可能不仅只有一个;当失效的 token 更新后,怎样将多个失败的请求,重新发送?操作流程好了!经过了一番分析后,我们找到了问题的所在,并且确定了切入点;那么接下来让我们实操,将问题解决掉。 「前要:」 1、我们仅从前端的角度去处理。 2、后端提供了两个重要的参数:accessToken(用于请求头中,进行鉴权,存在有效期);refreshToken(刷新令牌,用于更新过期的 accessToken,相对于 accessToken 而言,它的有效期更长)。 1、处理 axios 响应拦截「注:在我实际的项目中,accessToken 过期后端返回的 statusCode 值为 401,需要在axiosInstance.interceptors.response.use 的 error回调中进行逻辑处理。」 //响应拦截 axiosInstance.interceptors.response.use( (response)={ returnresponse; }, (error)={ let{ data,config }=error.response; returnnewPromise((resolve,reject)={ /** *判断当前请求失败 *是否由toekn失效导致的 */ if(data.statusCode===401){ /** *refreshToken为封装的有关更新token的相关操作 */ refreshToken(()={ resolve(axiosInstance(config)); }else{ reject(error.response); } }) } ) 我们通过判断statusCode来确定,是否当前请求失败是由token过期导致的;使用 Promise 处理将失败的请求,将由于 token 过期导致的失败请求存储起来(存储的是请求回调函数,resolve 状态)。「理由:后续我们更新了 token 后,可以将存储的失败请求重新发起,以此来达到用户无感的体验」「补充:」「现象」:在我过了几天登录平台的时候发现,refreshToken过期了,但是没有跳转到登录界面「原因」: 1、当refreshToken过期失效后,后端返回的状态码也是 401 2、发起的更新token的请求采用的也是处理后的axios,因此「响应失败的拦截,对更新请求同样适用」。 「问题:」 这样会造成,当refreshToken过期后,会出现停留在首页,无法跳转到登录页面。 「解决方法」 针对这种现象,我们需要完善一下axios中响应拦截的逻辑。 axiosInstance.interceptors.response.use( (response)={ returnresponse; }, (error)={ let{ data,config }=error.response; returnnewPromise((resolve,reject)={ /** *判断当前请求失败 *是否由toekn失效导致的 */ if( data.statusCode===401&& config.url!=='/api/token/refreshToken' ){ refreshToken(()={ resolve(axiosInstance(config)); }elseif( data.statusCode===401&& config.url==='/api/token/refreshToken' ){ /** *后端更新refreshToken失效后 *返回的状态码,401 */ window.location.href=`${HOME_PAGE}/login`; }else{ reject(error.response); } }) } ) 2、封装 refreshToken 逻辑「要点:」 存储由于token过期导致的失败的请求。更新本地以及axios中头部的token。当 refreshToken 刷新令牌也过期后,让用户重新登录。//存储由于token过期导致失败的请求 letexpiredRequestArr:any[]= /** *存储当前因为token失效导致发送失败的请求 */ constsaveErrorRequest=(expiredRequest:()=any)={ expiredRequestArr.push(expiredRequest); } //避免频繁发送更新 letfirstRequre=true; /** *利用refreshToken更新当前使用的token */ constupdateTokenByRefreshToken=()={ firstRequre=false; axiosInstance.post( '更新token的请求', ).then(res={ let{ refreshToken,accessToken }=res.data; //更新本地的token localStorage.setItem('accessToken',accessToken); //更新请求头中的token setAxiosHeader(accessToken); localStorage.setItem('refreshToken',refreshToken); /** *当获取了最新的refreshToken,accessToken后 *重新发起之前失败的请求 */ expiredRequestArr.forEach(request={ request(); }) expiredRequestArr= }).catch(err={ console.log('刷新token失败err',err); /** *此时refreshToken也已经失效了 *返回登录页,让用户重新进行登录操作 */ window.location.href=`${HOME_PAGE}/login`; }) } /** *更新当前已过期的token *@paramexpiredRequest回调函数,返回由token过期导致失败的请求 */ exportconstrefreshToken=(expiredRequest:()=any)={ saveErrorRequest(expiredRequest); if(firstRequre){ updateTokenByRefreshToken(); } } 「补充:」「问题:」 1、怎么能保证当更新token后,在处理存储的过期请求时,此时没有过期请求还在存呢?;万一此时还在expiredRequestArr推失败的请求呢? 「解决方法」我们需要调整一下更新 token的逻辑,确保当前由于过期失败的请求都接收到了,再更新token然后重新发起请求。 「最终结果:」//refreshToken.ts /** *功能: *用于实现无感刷新token */ import{axiosInstance,setAxiosHeader}from"@/axios" import{CLIENT_ID,HOME_PAGE}from"@/systemInfo" //存储由于token过期导致失败的请求 letexpiredRequestArr:any[]= /** *存储当前因为token失效导致发送失败的请求 */ constsaveErrorRequest=(expiredRequest:()=any)={ expiredRequestArr.push(expiredRequest); } /** *执行当前存储的由于过期导致失败的请求 */ constagainRequest=()={ expiredRequestArr.forEach(request={ request(); }) clearExpiredRequest(); } /** *清空当前存储的过期请求 */ exportconstclearExpiredRequest=()={ expiredRequestArr= } /** *利用refreshToken更新当前使用的token */ constupdateTokenByRefreshToken=()={ axiosInstance.post( '更新请求url', { clientId:CLIENT_ID, userName:localStorage.getItem('userName') }, { headers:{ 'Content-Type':'application/json;charset=utf-8', 'Authorization':'bearer'+localStorage.getItem("refreshToken") } } ).then(res={ let{ refreshToken,accessToken }=res.data; //更新本地的token localStorage.setItem('accessToken',accessToken); localStorage.setItem('refreshToken',refreshToken); setAxiosHeader(accessToken); /** *当获取了最新的refreshToken,accessToken后 *重新发起之前失败的请求 */ againRequest(); }).catch(err={ /** *此时refreshToken也已经失效了 *返回登录页,让用户重新进行登录操作 */ window.location.href=`${HOME_PAGE}/login`; }) } lettimer:any=null; /** *更新当前已过期的token *@paramexpiredRequest回调函数,返回过期的请求 */ exportconstrefreshToken=(expiredRequest:()=any)={ saveErrorRequest(expiredRequest); //保证再发起更新时,已经没有了过期请求要进行存储 if(timer)clearTimeout(timer); timer=setTimeout(()={ updateTokenByRefreshToken(); },500); } //响应拦截区分登录前 axiosInstance.interceptors.response.use( (response)={ returnresponse; }, (error)={ let{ data,config }=error.response; returnnewPromise((resolve,reject)={ /** *判断当前请求失败 *是否由toekn失效导致的 */ if( data.statusCode===401&& config.url!=='/api/token/refreshToken' ){ refreshToken(()={ resolve(axiosInstance(config)); }elseif( data.statusCode===401&& config.url==='/api/token/refreshToken' ){ /** *后端更新refreshToken失效后 *返回的状态码,401 */ clearExpiredRequest(); window.location.href=`${HOME_PAGE}/login`; }else{ reject(error.response); } }) } ) 补充感谢很多朋友提出了很多更好的方法;我写这篇文章主要是为了分享一下,恰好这种问题推到了我(前端工程师)身上,我是怎样处理的;虽然有可能在一些朋友看来很低级,但它确是我实际工作中碰到的问题,每一个问题的出现解决后都对自身是一种成长,通过分享的方式来巩固自己,也希望能对他人有一些帮助! 总结经过一波分析以及操作,我们最终实现了实际项目中的无感刷新token,最主要的是有效避免了:用户在平台操作过程中突然要退出登录的现象(「尤其是当用户进行信息填写,突然要重新登录,之前填写的信息全部作废,是很容易让人发狂的」)。 其实回顾一下,技术上并没有什么难点,只是思路上自己是否能够想通、自洽。人是一棵会思想的芦苇,我们要有自己的思想,面对问题,有自己的思考。 希望我们能在技术的路上走的越来越远,与君共勉!!! 点击关注公众号回复”小册” 优惠券免费领!! 阅读原文

上一篇:2024-06-07_阿里Qwen2正式开源,性能全方位包围Llama-3 下一篇:2025-05-13_都2025年了,你还在提交按钮上面用防抖函数?

TAG标签:

16
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价