翼度科技»论坛 编程开发 JavaScript 查看内容

VUE中拦截请求并无感知刷新token方式

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
VUE拦截请求并无感知刷新token


应用场景

前端登录后,后端返回token和token失效时间,当达到特定条件(本文以距离token过期两小时为例),前端需要主动请求token刷新接口去获取一个新的token,做到用户无感知地去刷新token。

思路

拦截请求判断是否达到需要刷新token的条件,符合条件则刷新token并将请求存入一个重试队列中,当token刷新后,执行重试队列中的函数,达到刷新token的效果,
需要注意的是,当多个请求几乎同时进来时,为了避免多次执行token刷新,需要定义一个变量(本文变量名为isRefreshing )进行标记。
  1. import axios from "axios";
  2. import store from "@/store";
  3. import md5 from "js-md5";
  4. import {
  5.   setToken,
  6.   getToken,
  7.   setUid,
  8.   setExpireTime,
  9.   getExpireTime
  10. } from "@/utils/auth";

  11. // 创建axios实例
  12. const service = axios.create({
  13.   // axios中请求配置有baseURL选项,表示请求URL公共部分
  14.   baseURL: window.location.protocol + process.env.VUE_APP_BASE_API,
  15.   // 超时
  16.   timeout: 10000
  17. });

  18. // 是否正在刷新的标记
  19. let isRefreshing = false;

  20. // 重试队列,每一项将是一个待执行的函数形式
  21. let requests = [];

  22. // 判断是否距离过期2个小时
  23. function isRefreshTokenExpired() {
  24.   const expire_time = getExpireTime(); // 到期时间
  25.   const new_time = new Date().getTime(); // 当前时间
  26.   const stamp = expire_time - new_time; // 距离到期时间
  27.   return stamp <= 2 * 60 * 60 * 1000 ? true : false; // 2小时
  28. }

  29. // request拦截器
  30. service.interceptors.request.use(
  31.   config => {
  32.     const tokenObj = getToken();
  33.     if (config.data.method === "xxxx") { //当请求的接口为token刷新接口时
  34.       return config;
  35.     }
  36.     if (tokenObj && isRefreshTokenExpired()) {
  37.       // 立即刷新token
  38.       if (!isRefreshing) {
  39.         isRefreshing = true;
  40.         // 请求token刷新接口
  41.         store
  42.           .dispatch("RefeshToken")
  43.           .then(res => {
  44.             const token = res.data.token;
  45.             const time = res.data.expire_time.replace(/-/g, "/");
  46.             const expire_time = new Date(time);
  47.             setToken(token, expire_time);
  48.             setExpireTime(new Date(res.data.expire_time).getTime(), expire_time);
  49.             setUid(res.data.uid, expire_time);
  50.             isRefreshing = false;
  51.             return token;
  52.           })
  53.           .then(token => {
  54.             requests.forEach(cb => cb(token));
  55.             // 执行完成后,清空队列
  56.             requests = [];
  57.           })
  58.           .catch(res => {
  59.             console.error("refresh token error: ", res);
  60.           });
  61.       }
  62.       const retryOriginalRequest = new Promise(resolve => {
  63.         requests.push(token => {
  64.           // 因为config中的token是旧的,所以刷新token后要将新token传进来
  65.           config.headers["ContentToken"] = token;
  66.           resolve(config);
  67.         });
  68.       });
  69.       return retryOriginalRequest;
  70.     }
  71.     return config;
  72.   },
  73.   error => {
  74.     Promise.reject(error);
  75.   }
  76. );

  77. // 响应拦截器
  78. service.interceptors.response.use(
  79.   res => {
  80.     if (res.status === 200) {
  81.             return res
  82.     }
  83.   },
  84.   error => {
  85.            console.log('catch', error)
  86.           return Promise.reject(error)
  87.   }
  88. );

  89. export default service;
复制代码
总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

来源:https://www.jb51.net/javascript/326741v10.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具