美文网首页
如何挂起Promise请求,refresh_token后再用新的

如何挂起Promise请求,refresh_token后再用新的

作者: 我是滕先生 | 来源:发表于2020-04-05 22:36 被阅读0次

接手老项目,需要写一个access_token刷新的逻辑,具体流程我就不赘述了,网上关于JWT刷新流程的文章有很多。我遇到的主要问题是,项目没有使用axios,原生的fetch没有拦截器,对于多次同时刷新token的请求是应该做拦截处理的,待第一个刷新请求回调后再发起后续被拦截请求,业务场景和这篇文章类似,难点在于如何挂起请求,直接贴代码。

  let isRefreshing = false; // 用于拦截鉴权失败的请求
  let pendingRequests = []; // 被拦截请求的缓存池

  // 持久化token,我是写cookie里的
  const storeToken = function (data) {
    const { access_token, refresh_token } = data;
    const duration = 60 * 60 * 1; // 持续时间-秒
    ctx.app.$cookie('accessToken', access_token, { expires: duration });
    ctx.app.$cookie('refreshToken', refresh_token, { expires: duration });
  };

  const refreshToken = async function () {
    isRefreshing = true;
    try {
      // 换取token的请求
      const res = await $jfetch.post('/japi/v1/auth?grant_type=refresh_token', {
        body: {
          refresh_token: ctx.app.$cookie('refreshToken'),
        },
      });
      storeToken(res.data);
      isRefreshing = false;
      const newAccesssToken = res.data.access_token;
      // 用新的token重新发起待定池中的请求
      pendingRequests.forEach((item) => {
        item.resolved(newAccesssToken);
      });
      // 清空缓存池
      pendingRequests = [];
      return newAccesssToken;
    } catch (error) {
      isRefreshing = false;
      return null;
    }
  };

  const getCookieToken = async function () {
    // 避免重复发起刷新
    if (isRefreshing) return;
    const accessToken = ctx.app.$cookie('accessToken');
    if (!accessToken) {
      return await refreshToken();
    }
    return accessToken;
  };

  const getAccessToken = async function () {
    // 取到为空的表示是该被拦截的
    const accessToken = await getCookieToken();
    // 将被拦截的请求挂起 存到缓存池中
    if (!accessToken) {
      // 重点
      const externalControl = {
        resolved: null,
      };
      // 这里返回了一个新的Promise变相的实现请求的挂起(只要没有resolved或rejected,请求就会一直处于pedding状态)
      // 并将Promise状态的改变放到了外部一个对象来控制 externalControl ,待定池缓存这个对象即可,待需要执行后续被拦截请求,只需要利用这个对象引用的 resolved 来改变Promise状态即可实现请求挂起的放行
      const interceptPromise = new Promise((resolved) => {
        externalControl.resolved = resolved;
      });
      pendingRequests.push(externalControl);
      return interceptPromise;
    }
    return accessToken;
  };

在需要鉴权的接口调用,这里还缺少refresh_token失效跳转到登录页的逻辑,自行填补:
headers['Authorization'] = await getAccessToken();

相关文章

  • 如何挂起Promise请求,refresh_token后再用新的

    接手老项目,需要写一个access_token刷新的逻辑,具体流程我就不赘述了,网上关于JWT刷新流程的文章有很多...

  • Promise 和async/awiat

    Promise Promise的作用,promise如何进行多个数据的请求 Promise对象代表一个异步操作,有...

  • 同步执行

    Promise 与async 请求结束后执行then ()

  • Promise&async/await

    Promise Promise有三种状态: pending(挂起) fulfilled(成功) rejecte...

  • vue项目打包部署后请求地址及请求问题

    1 首先 vue中 是用的axios 发请求, axios 支持Promise 非常好用, 可以在请求后的.the...

  • Promise

    Promise对象就是一个异步请求占位符对象 把异步请求封装在Promise对象中,Promise的构造函数传入一...

  • 2018-12-06 解决多异步请求,和树结构扁平化

    1.解决for循环发异步请求,并确定全部请求返回后 开始回调 Promise.all(reqs).then(fun...

  • promise(ES6)

    promise.all 多个起步请求,要所有的请求都拿到结果了再执行操作 promise.race 多个请求,只...

  • iOS Promise学习小结

    一、Promise概述 1、为什么引入Promise 在日常开发中,异步操作是很常见的情况,比如发起网络请求后,处...

  • ES6

    AJAX 异步网络请求 Promise 使用了Promise对象之后可以链式调用的方式组织代码 Promise.a...

网友评论

      本文标题:如何挂起Promise请求,refresh_token后再用新的

      本文链接:https://www.haomeiwen.com/subject/dsapphtx.html