js无痛刷新Token的实现
这个需求场景很常见,几乎很多项目都会用上,之前项目也实现过,最近刚好有个项目要实现,重新梳理一番。
需求
对于需要前端实现无痛刷新Token,无非就两种:
- 请求前判断Token是否过期,过期则刷新
- 请求后根据返回状态判断是否过期,过期则刷新
- 判断
Token
是否过期 没过期则正常处理
过期则发起刷新Token
的请求 拿到新的Token
保存
重新发送Token
过期这段时间内发起的请求
- 保持
Token
过期这段时间发起请求状态(不能进入失败回调) - 把刷新
Token
后重新发送请求的响应数据返回到对应的调用者
- 创建一个flag
isRefreshing
来判断是否刷新中 - 创建一个数组队列
retryRequests
来保存需要重新发起的请求 - 判断到
Token
过期isRefreshing = false
的情况下 发起刷新Token
的请求刷新Token
后遍历执行队列retryRequests
isRefreshing = true
表示正在刷新Token
,返回一个Pending
状态的Promise
,并把请求信息保存到队列retryRequests
中
import 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; //刷新Tokenreturn Store.dispatch("user/relogin").then(res => {// 设置刷新后的Tokenconfig.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(() => {// 请求完成后重置flagisRefreshing = 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的实现的文章就介绍到这了,更多相关js无痛刷新Token内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读
- vue|vue导航栏自定义设置带图片(选中状态刷新不消失)
- 新版Postman设置所有请求都自动带token登陆权限验证(Postman 版本9.10.0 )
- Django|Vue + Django 2.0.6 学习笔记 7.1 drf的token登录
- 《关于在A页面操作B页面刷新数据这件事》
- 2月券商App行情刷新及交易体验报告,东方与安信升至领导者象限
- 【JS 逆向百例】拉勾网爬虫,traceparent、__lg_stoken__、X-S-HEADER 等参数分析
- Feign如何解决服务之间调用传递token
- 服务器|彻底搞懂Cookie、Session、JWT和Token(强烈推荐)《彻底搞懂Cookie、Session、JWT和Token|CSDN创作打卡》
- vue history路由模式下ios微信分享首次签名失败,二次刷新后成功
- ASP.NET|ASP.NET Core 简单集成签发 JWT (JSON Web Tokens)