js无痛刷新Token的实现

js无痛刷新Token的实现

这个需求场景很常见,几乎很多项目都会用上,之前项目也实现过,最近刚好有个项目要实现,重新梳理一番。

需求

对于需要前端实现无痛刷新Token,无非就两种:

请求前判断Token是否过期,过期则刷新

请求后根据返回状态判断是否过期,过期则刷新

处理逻辑

实现起来也没多大差别,只是判断的位置不一样,核心原理都一样:

判断Token是否过期

没过期则正常处理

过期则发起刷新Token的请求

拿到新的Token保存

重新发送Token过期这段时间内发起的请求

重点:

保持Token过期这段时间发起请求状态(不能进入失败回调)

把刷新Token后重新发送请求的响应数据返回到对应的调用者

实现

创建一个flag isRefreshing 来判断是否刷新中

创建一个数组队列retryRequests来保存需要重新发起的请求

判断到Token过期isRefreshing = false 的情况下 发起刷新Token的请求

刷新Token后遍历执行队列retryRequests

isRefreshing = true 表示正在刷新Token,返回一个Pending状态的Promise,并把请求信息保存到队列retryRequestsimport axios from "axios"; import Store from "@/store"; import Router from "@/router"; import { Message } from "element-ui"; import UserUtil from "@/utils/user"; // 创建实例 const Instance = axios.create(); Instance.defaults.baseURL = "/api"; Instance.defaults.headers.post["Content-Type"] = "application/json"; Instance.defaults.headers.post["Accept"] = "application/json"; // 定义一个flag 判断是否刷新Token中 let isRefreshing = false; // 保存需要重新发起请求的队列 let retryRequests = []; // 请求拦截 Instance.interceptors.request.use(async function(config) { Store.commit("startLoading"); const userInfo = UserUtil.getLocalInfo(); if (userInfo) { //业务需要把Token信息放在 params 里面,一般来说都是放在 headers里面 config.params = Object.assign(config.params ? config.params : {}, { appkey: userInfo.AppKey, token: userInfo.Token }); } return config; }); // 响应拦截 Instance.interceptors.response.use( async function(response) { Store.commit("finishLoading"); const res = response.data; if (res.errcode == 0) { return Promise.resolve(res); } else if ( res.errcode == 30001 || res.errcode == 40001 || res.errcode == 42001 || res.errcode == 40014 ) { // 需要刷新Token 的状态 30001 40001 42001 40014 // 拿到本次请求的配置 let config = response.config; // 进入登录页面的不做刷新Token 处理 if (Router.currentRoute.path !== "/login") { if (!isRefreshing) { // 改变flag状态,表示正在刷新Token中 isRefreshing = true; // 刷新Token return Store.dispatch("user/relogin") .then(res => { // 设置刷新后的Token config.params.token = res.Token; config.params.appkey = res.AppKey; // 遍历执行需要重新发起请求的队列 retryRequests.forEach(cb => cb(res)); // 清空队列 retryRequests = []; return Instance.request(config); }) .catch(() => { retryRequests = []; Message.error("自动登录失败,请重新登录"); const code = Store.state.user.info.CustomerCode || ""; // 刷新Token 失败 清空缓存的用户信息 并调整到登录页面 Store.dispatch("user/logout"); Router.replace({ path: "/login", query: { redirect: Router.currentRoute.fullPath, code: code } }); }) .finally(() => { // 请求完成后重置flag isRefreshing = false; }); } else { // 正在刷新token,返回一个未执行resolve的promise // 把promise 的resolve 保存到队列的回调里面,等待刷新Token后调用 // 原调用者会处于等待状态直到 队列重新发起请求,再把响应返回,以达到用户无感知的目的(无痛刷新) return new Promise(resolve => { // 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行 retryRequests.push(info => { // 将新的Token重新赋值 config.params.token = info.Token; config.params.appkey = info.AppKey; resolve(Instance.request(config)); }); }); } } return new Promise(() => {}); } else { return Promise.reject(res); } }, function(error) { let err = {}; if (error.response) { err.errcode = error.response.status; err.errmsg = error.response.statusText; } else { err.errcode = -1; err.errmsg = error.message; } Store.commit("finishLoading"); return Promise.reject(err); } ); export default Instance;

到此这篇关于js无痛刷新Token的实现的文章就介绍到这了,更多相关js无痛刷新Token内容请搜索易知道(ezd.cc)以前的文章或继续浏览下面的相关文章希望大家以后多多支持易知道(ezd.cc)!

推荐阅读

    js设置div的边框|怎样给div设置边框

    js设置div的边框|怎样给div设置边框,,1. 怎样给div设置边框1、首先新建一个html文件,输入基本的内容,这里设置一个div,并把它的class设置为de

    js设置样式|js设置样式类

    js设置样式|js设置样式类,,js设置样式    javascript改变CSS样式分为局部和全局,分别如下:  一、局部改变样式    有三种方法:直接

    js用代码实现简单购物车

    js用代码实现简单购物车,,图: 选择所有按钮: 复制代码代码如下所示: 选择 笔记本电脑:3000元 笔记本电脑:3000元 笔记本电脑:3000元 笔记本电脑:3

    js设置背景色|js设置颜色

    js设置背景色|js设置颜色,,js设置背景色首先通过js定位到div的子元素,再通过setatteibute方法给属性添加背景色。js设置颜色js改变字体的颜

    Safari调试iOS中的js

    Safari调试iOS中的js,页面,设备,概述对于HTML5的开发,大家都知道Chrome的DevTools工具有强大的功能和友好的用户体验,不仅能快速方便调试Jav

    Bootstrap的js插件之模态框|modal

    Bootstrap的js插件之模态框|modal,模态,饭盒,.modal——指明div元素包裹模态框;.fade——给模态框添加淡入淡出效果;.modal-dialog——包裹

    js默认事件汇总

    js默认事件汇总,事件,表单,默认事件   就是浏览器通过HTML标签或DOM元素提供的一些功能性的默认行为。比如在a标签href属性上的跳转,右键

    js获取元素宽度

    js获取元素宽度,内联,样式,js获取元素宽度1、使用内联样式,即直接把CSS写在HTML元素的style属性中<div > </div>复制代码通过以下js代码

    SQLite使用JSON扩展

    SQLite使用JSON扩展,插件,加载,一、介绍 SQLite3.9.0之后的版本,添加了JSON扩展。在表中可以保存JSON类型。实际上SQLite将JSON类型的

    jscript.dll是什么

    jscript.dll是什么,系统,文件,论坛,显示,扫描,修复,  jscript.dll是Microsoft JavaScript脚本支持相关文件。属于: Microsoft JScript系统 DLL

    postgresql中对jsonb的查询及转换

    postgresql中对jsonb的查询及转换,数据,字段,表数据:需要将strata排除,并且过滤info字段中为{}的数据,将jsonb转换成text,替换“,{,}见SQL:sele