无感刷新 token

线上平台有时会出现用户正在使用的时候,突然要用户去进行登录,这样会造成很不好的用户体验,但是当时一直没有好的思路因此搁置了下来;通过零散时间查询资料以及思考,最终解决了这个问题,接下来跟大家分享一下!

环境

  • 请求采用的 Axios V1.3.2。

  • 平台的采用的 JWT(JSON Web Tokens) 进行用户登录鉴权。

    拓展:JWT 是一种认证机制,让后台知道该请求是来自于受信的客户端;更详细的可以自行查询相关资料

问题现象

线上用户在使用的时候,偶尔会出现突然跳转到登录页面,需要重新登录的现象。

原因

  • 突然跳转到登录页面,是由于当前的 token 过期,导致请求失败;在 axios 的响应拦截axiosInstance.interceptors.response.use中处理失败请求返回的状态码 401,此时得知token失效,因此跳转到登录页面,让用户重新进行登录。

  • 平台目前的逻辑是在 token 未过期内,用户登录平台可直接进入首页,无需进行登录操作;因此就存在该现象:用户打开平台,由于此时 token 未过期,用户直接进入到了首页,进行其他操作。但是在用户操作的过程中,token 突然失效了,此时就会出现突然跳转到登录页面,严重影响用户的体验感!
    注:目前线上项目中存在数据大屏,一些实时数据的显示;因此存在用户长时间停留在大屏页面,不进行操作,查看实时数据的情况

切入点

  • 怎样及时的、在用户感知不到的情况下更新token

  • 当 token 失效的情况下,出错的请求可能不仅只有一个;当失效的 token 更新后,怎样将多个失败的请求,重新发送?

操作流程

好了!经过了一番分析后,我们找到了问题的所在,并且确定了切入点;那么接下来让我们实操,将问题解决掉。

  • 我们仅从前端的角度去处理。

  • 后端提供了两个重要的参数:accessToken(用于请求头中,进行鉴权,存在有效期);refreshToken(刷新令牌,用于更新过期的 accessToken,相对于 accessToken 而言,它的有效期更长)。

1、处理 axios 响应拦截

注:在我实际的项目中,accessToken 过期后端返回的 statusCode 值为 401,需要在axiosInstance.interceptors.response.use 的 error回调中进行逻辑处理。

// 响应拦截
axiosInstance.interceptors.response.use((response) => {return response;},(error) => {let {data, config} = error.response;return new Promise((resolve, reject) => {/*** 判断当前请求失败* 是否由 toekn 失效导致的*/if (data.statusCode === 401) {/*** refreshToken 为封装的有关更新 token 的相关操作*/refreshToken(() => {resolve(axiosInstance(config));});} else {reject(error.response);}})}
)
  1. 我们通过判断statusCode来确定,是否当前请求失败是由token过期导致的;

  2. 使用 Promise 处理将失败的请求,将由于 token 过期导致的失败请求存储起来(存储的是请求回调函数,resolve 状态)。

理由:后续我们更新了 token 后,可以将存储的失败请求重新发起,以此来达到用户无感的体验

补充:

现象:在我过了几天登录平台的时候发现,refreshToken过期了,但是没有跳转到登录界面 原因

  • 当 refreshToken 过期失效后,后端返回的状态码也是 401

  • 发起的更新token的请求采用的也是处理后的axios,因此响应失败的拦截,对更新请求同样适用

问题:

这样会造成,当 refreshToken 过期后,会出现停留在首页,无法跳转到登录页面。

 

解决方法

针对这种现象,我们需要完善一下axios中响应拦截的逻辑。

axiosInstance.interceptors.response.use((response) => {return response;},(error) => {let {data, config} = error.response;return new Promise((resolve, reject) => {/*** 判断当前请求失败* 是否由 toekn 失效导致的*/if (data.statusCode === 401 &&config.url !== '/api/token/refreshToken') {refreshToken(() => {resolve(axiosInstance(config));});} else if (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 过期导致 失败的请求
let expiredRequestArr: any[] = [];/*** 存储当前因为 token 失效导致发送失败的请求*/
const saveErrorRequest = (expiredRequest: () => any) => {expiredRequestArr.push(expiredRequest);
}// 避免频繁发送更新
let firstRequre = true;
/*** 利用 refreshToken 更新当前使用的 token*/
const updateTokenByRefreshToken = () => {firstRequre = false;axiosInstance.post('更新 token 的请求',).then(res => {let {refreshToken, accessToken} = res.data;// 更新本地的tokenlocalStorage.setItem('accessToken', accessToken);// 更新请求头中的 tokensetAxiosHeader(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* @param expiredRequest 回调函数,返回由token过期导致失败的请求*/
export const refreshToken = (expiredRequest: () => any) => {saveErrorRequest(expiredRequest);if (firstRequre) {updateTokenByRefreshToken();}
}

总结

经过一波分析以及操作,我们最终实现了实际项目中的无感刷新token,最主要的是有效避免了:用户在平台操作过程中突然要退出登录的现象(尤其是当用户进行信息填写,突然要重新登录,之前填写的信息全部作废,是很容易让人发狂的)。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/98856.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JavaEE】多线程进阶(一)饿汉模式和懒汉模式

多线程进阶(一) 文章目录 多线程进阶(一)单例模式饿汉模式懒汉模式 本篇主要引入多线程进阶的单例模式,为后面的大冰山做铺垫 代码案例介绍 单例模式 非常经典的设计模式 啥是设计模式 设计模式好比象棋中的 “棋谱”…

MySQL之Alter语句用法总结

1:删除列 ALTER TABLE 【表名字】 DROP 【列名称】 2:增加列 ALTER TABLE 【表名字】 ADD 【列名称】 INT NOT NULL COMMENT 注释说明 3:修改列的类型信息 ALTER TABLE 【表名字】 CHANGE 【列名称】【新列名称(这里可以用和原来列同名…

服务器启用SGX(以PowerEdge R750为例)

一、检查处理器是否支持SGX 在shell中输入以下命令查看CPU型号 cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c在Product Specifications中找到对应的处理器参数信息,如果支持SGX,可以在Security & Reliability中看到如下信息 二、以“软…

初学者如何选择:前端开发还是后端开发?

#开发做前端好还是后端好【话题征文】# 作为一名有多年开发经验的过来人,我认为前端开发和后端开发都有其独特的魅力和挑战。下面我将就我的个人经历和观点来分享一些关于前端开发和后端开发的看法。 首先,让我们将编程世界的大城市比作前端开发和后端开…

Spring:注解方式启用AOP

EnableAspectJAutoProxy proxyTargetClasstrue:强制使用cglib动态代理 exposeProxytrue在当前线程暴露代理对象,这样就可以通过AopContext.currentProxy来拿到代理对象 package cn.edu.tju.service5;import org.springframework.aop.framework.AopContext; import org.springf…

Git 学习笔记 | Git 基本理论

Git 学习笔记 | Git 基本理论 Git 学习笔记 | Git 基本理论Git 工作区域Git 工作流程 Git 学习笔记 | Git 基本理论 在开始使用 Git 创建项目前,我们先学习一下 Git 的基础理论。 Git 工作区域 Git本地有三个工作区域:工作目录(Working Di…

Unity实现设计模式——备忘录模式

Unity实现设计模式——备忘录模式 它可以在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态,以便在需要的时候恢复到原先保存的状态。 源发器(Originator):需要保存和恢复状态的对象。它创建一…

计算机网络笔记3 数据链路层

计算机网络系列笔记目录👇 计算机网络笔记6 应用层计算机网络笔记5 运输层计算机网络笔记4 网络层计算机网络笔记3 数据链路层计算机网络笔记2 物理层计算机网络笔记1 概述 文章前言 💗 站在巨人的肩膀上,让知识的获得更加容易&#xff01…

vue,前端打包项目、部署上线

前端项目是在本地的IDE开发的。流程是:开发》打包》上线到生产环境》使用。 vue脚手架只是开发过程中,协助开发的工具,当真正开发完了,脚手架不参与上线。 这时候要用到打包了。 打包后,可以生成,浏览器能够直接运行的网页>就是需要上线的源码! 打…

gradle使用笔记整理

idea中build时候中文乱码报错 Help -> Edit Custom VM Options文件末尾追加:-Dfile.encodingUTF-8 其他配置 修改gradle/wrapper/gradle-wrapper.properties中的distributionUrl为本地zip文件distributionUrlfile:///D:/tools/gradle/gradle-7.4.2-bin.ziplom…

Clion中使用C/C++开发stm32程序

前言 从刚开始学习阶段,一直是用的keil5开发stm32程序,自从看到稚晖君推荐的CLion开发嵌入式程序后,这次尝试在CLion上开发stm32程序。 1、配置CLion用于STM32开发的环境 这里我就不详细写了,没必要重新写,网上教程很多…

每日一练 | 华为认证真题练习Day117

1、缺省情况下,广播网络上OSPF协议Deadtime是? A. 20s B. 40s C. 10s D. 30s 2、当两台OSPF路由器形成TWO-WAY邻居关系时,LSDB已完成同步,但是SPF算法尚未运行。 A. 对 B. 错 3、以下哪种协议不属于文件传输协? …

【二分】Pythagorean Triples—CF1487D

Pythagorean Triples—CF1487D 思路 联立 a 2 b c 2 a^2 b c^2 a2bc2、 a 2 b 2 c 2 a^2 b^2 c^2 a2b2c2 得: a 2 2 ∗ c − 1 a^2 2 * c - 1 a22∗c−1、 b c − 1 b c - 1 bc−1。 对于一个固定的 a a a, b b b、 c c c 的值都是固定…

华为OD机试 - 数字反转打印(Java 2023 B卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷&#…

二进制中左移、右移、无符号右移规则

前提知识 正数的原码&#xff0c;反码以及补码都是一样的负数的反码是原码的符号位不变&#xff0c;数值位按位取反负数的补码是符号位不变&#xff0c;数值位在反码的基础上加1正数的符号位是用0来表示&#xff0c;负数的符号位使用1来表示 二进制左移&#xff08;<<&…

dataframe保存excel格式比csv格式小很多很多

问题描述&#xff1a; 一个3万行的数据保存成csv大概10个G&#xff0c;但保存成excel格式只有100多M 原因分析&#xff1a; 因为xlsx 实际上就是 zip 压缩包&#xff0c;同时&#xff0c;如果有大量重复的数据&#xff0c;XLSX 会提取文本值&#xff0c;将其存储在查找表中&…

机器学习基础-Pandas学习笔记

Pandas Python的数据分析库&#xff0c;与Numpy配合使用&#xff0c;可以从常见的格式如CSV、JSON等中读取数据。可以进行数据清洗、数据加工工作。数据结构Series&#xff0c;Pandas.Series(data,index,dtype,name,copy) data类型是Numpy的ndarray类型&#xff0c;index指定下…

华为云云耀云服务器L实例评测|部署项目管理工具 Focalboard

华为云云耀云服务器L实例评测&#xff5c;部署项目管理工具 Focalboard 一、云耀云服务器L实例介绍1.1 云服务器介绍1.2 产品优势1.3 产品规格1.4 应用场景 二、云耀云服务器L实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 Focalboard3.1 Focalboard 介绍3.2 Doc…

springboot3+grpc+zipkin+Micrometer配置

1. maven依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.2</version></parent><properties><java.version>21</java.version>…

2023年中国CEM-1型覆铜板产量、需求量及行业销售收入分析[图]

CEM-1指覆铜板的一种&#xff0c;以玻纤布半固化片与纸基半固化片层压铜箔达到固化后形成的板材&#xff0c;属于复合型基材&#xff0c;CEM-1能用来制作频率特性要求高的PCB&#xff0c;如电视机的调谐器、电源开关、超声波设备、计算机电源和键盘&#xff0c;也可以用于电视机…