我的编程空间,编程开发者的网络收藏夹
学习永远不晚

js无痛刷新Token的实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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;
        //   刷新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内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

js无痛刷新Token的实现

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

uniapp无痛刷新token的方法介绍

本篇文章和大家了解一下uniapp无痛刷新token的方法介绍。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。前端在请求接口时,和后端定义好了,如果状态码为 401 ,则表明 token 过期,需要前端请求新的 token
2023-06-15

Vue3+Vite使用双token实现无感刷新

本文主要介绍了Vue3+Vite使用双token实现无感刷新,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-05-17

详细聊聊前端如何实现token无感刷新(refresh_token)

实现token无感刷新对于前端来说是一项非常常用的技术,其本质是为了优化用户体验,下面这篇文章主要给大家介绍了关于前端如何实现token无感刷新(refresh_token)的相关资料,需要的朋友可以参考下
2022-11-13

ASP.NET Core怎么实现自动刷新JWT Token

这篇文章主要介绍了ASP.NET Core怎么实现自动刷新JWT Token的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇ASP.NET Core怎么实现自动刷新JWT Token文章都会有所收获,下面我们一起
2023-06-30

django+js+ajax实现刷新页面的方法

本文实例讲述了django+js+ajax实现刷新页面的方法。分享给大家供大家参考,具体如下: 在服务器开发的时候,为了方便将服务器对外开一个接口来操作,可以使用django制作网页,通过页面来操作服务器。这样可以将服务器的维护工作暴漏在更
2022-06-04

js(jquery)实现无刷新跳转404页面不存在效果

有时候我们希望临时让某个分类或者多个文章不能正常访问,手动给html文件改名?或者改后台改程序?太麻烦了。用本文的js代码很容易实现,而且使用得当很隐蔽。这篇文章主要介绍了js(jquery)实现无刷新跳转404页面不存在效果,需要的朋友可以参考下
2023-05-17

pushState实现Ajax无刷新页面切换

可以通过使用pushState方法来实现Ajax无刷新页面切换。pushState方法可以向浏览器的历史记录中添加一个新的状态,并且不会引起页面的刷新。下面是一个简单的示例:1. HTML```html
2023-08-15

ASP.NET中怎么实现无刷新分页

本篇文章给大家分享的是有关ASP.NET中怎么实现无刷新分页,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1、新建一个分页存储过程:CREATE procedure [dbo]
2023-06-17

ajax实现无刷新分页的示例分析

这篇文章给大家分享的是有关ajax实现无刷新分页的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1、Ajax 无刷新页面的好处:提供良好的客户体验,通过 Ajax 在后台从数据库中取得数据并展示,取缔了等
2023-06-08

编程热搜

目录