在alovajs中无感刷新token

alova是一个轻量级的请求策略库,旨在简化接口的管理和使用。你可以通过简单配置参数,即可实现复杂请求如请求共享、分页请求、表单提交、断点续传等,无需编写大量代码,提高开发效率,应用性能,减轻服务端压力。

在请求时我们经常需要通过token授权登录,并在token过期时通过refresh_token刷新token,这边我们来讨论下如何通过alova来无感刷新token,即当发现token过期时自动刷新token,在请求发起处不会感觉到token已刷新。

以下提供了两种思路,每种思路都实现了token在刷新期间让其他请求等待的功能。

在前端判断token过期

这种是在前端判断token是否过期,这通常在登录时有返回token过期时间时使用,思路是在beforeRequest中判断token是否过期,已过期则先刷新token后继续发送请求,它的优点是不会接收到token过期的响应,因此也不需要重复发送请求。

js 复制代码
let token = '', refreshToken = '', tokenRefreshing = false, waitingList = [];
const alovaInstance = createAlova({
  // ...
  beforeRequest: async method => {
    if (getCache('token_expire_time') < Date.now() && method.meta?.authType !== 'refreshToken') { // token过期
      if (tokenRefreshing) {
        // 如果正在刷新token,则等待刷新完成后再发请求
        console.log('正在刷新token,等待请求');
        await new Promise(resolve => {
          waitingList.push(resolve);
        });
      }

      try {
        tokenRefreshing = true;
        const { refreshToken: newRefreshToken, token: newToken } = await tokenRefresh({ refreshToken });
        // 保存新的token和refreshToken
        token = newToken;
        refreshToken = newRefreshToken;

        tokenRefreshing = false;
        // 刷新token完成后,通知等待列表中的请求
        waitingList.forEach(resolve => resolve());
        waitingList = [];
      } catch(error) {
        // 刷新token失败,可以处理跳转到登录界面等操作
        // ...
      }
    }

    method.config.headers.Authorization = token;
  },
})

在这里tokenRefresh请求method添加了authType = 'refreshToken'的meta数据作为标识,才能通过请求。

js 复制代码
export const tokenRefresh = () => {
  const method = alovaInst.Get('/refresh-token', {
    localCache: null
  });
  method.meta = {
    authType: 'refreshToken'
  };
  return method;
}

通过服务端返回的状态判断token过期

这种方式是通过服务端的返回状态判断token是否过期,这通常在登录时没有返回token过期时间时使用,思路是在responded.onSuccess中通过返回状态判断token是否过期,已过期则刷新token后再次发送请求,它的优点是比较准确,但也会有重复的请求发送。

js 复制代码
let token = '', refreshToken = '';
let tokenRefreshing = false; // 正在刷新token,让其他请求先等着
let waitingList = [];
const alovaInst = createAlova({
  // ...
  beforeRequest: async ({ url, config, meta }) => {
    console.log(url, '正在请求');
    // 如果正在刷新token,则等待刷新完成后再发请求
    if (tokenRefreshing && meta?.authType !== 'refreshToken') {
      console.log('正在刷新token,等待请求');
      await new Promise(resolve => {
        waitingList.push(resolve);
      });
    }
    config.headers.Authorization = token;
  },
  responsed: async (response, method) => {
    if (response.status === 401) { // token过期
      console.log(method.url, 'token失效,重新获取token');
      try {
          // 这边防止请求多次刷新token,把在token刷新完成前发送的拦截并等待
          if (tokenRefreshing) {
            console.log('正在刷新token,等待请求');
            await new Promise(resolve => {
              waitingList.push(resolve);
            });
          })
        tokenRefreshing = true;
        const { token: newToken, refreshToken: newRefreshToken } = await refreshToken({ refreshToken });
        token = newToken;
        refreshToken = newRefreshToken;

        tokenRefreshing = false;
        waitingList.forEach(resolve => resolve());
        waitingList = [];
        console.log('已获得新token并保存', token, `再重新访问${method.url}`);

        // 这里因为是重新请求原接口,与上一次请求叠加会导致重复调用transformData,因此需要将transformData置空去除一次调用
        const methodTransformData = method.config.transformData;
        method.config.transformData = undefined;
        const dataResent = await method;
        method.config.transformData = methodTransformData;
        return dataResent;
      } catch(error) {
        // 刷新token失败,可以处理跳转到登录界面等操作
        // ...
      }
    }
    return response.json();
  },
});

至此alova的两种刷新token的思路都实现了,在请求发起处无感知token刷新。

想学习更多 alovajs 的用法,欢迎来alova 官网学习。如果你也喜欢 alovajs,请在Github 仓库中贡献一颗 star,这对我们非常重要。

如果觉得文章对你有帮助,请别吝啬你的赞和评论哈,说说你对 alovajs 怎么看的,或者可以问一些问题,我会尽量回答的,你的支持是我创作的最大动力!哈哈哈哈哈哈~

欢迎加入交流社区

有任何问题,你可以加入以下群聊咨询,也可以在github 仓库中发布 Discussions,如果遇到问题,也请在github 的 issues中提交,我们会在最快的时间解决。

同时也欢迎贡献你的一份力量,请移步贡献指南

往期文章

相关推荐
mCell7 小时前
GSAP ScrollTrigger 详解
前端·javascript·动效
gnip7 小时前
Node.js 子进程:child_process
前端·javascript
codingandsleeping13 小时前
使用orval自动拉取swagger文档并生成ts接口
前端·javascript
白水清风14 小时前
微前端学习记录(qiankun、wujie、micro-app)
前端·javascript·前端工程化
用户221520442780014 小时前
new、原型和原型链浅析
前端·javascript
阿星做前端14 小时前
coze源码解读: space develop 页面
前端·javascript
叫我小窝吧14 小时前
Promise 的使用
前端·javascript
前端康师傅16 小时前
JavaScript 作用域
前端·javascript
云枫晖16 小时前
JS核心知识-事件循环
前端·javascript
eason_fan16 小时前
Git 大小写敏感性问题:一次组件重命名引发的CI构建失败
前端·javascript