在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中提交,我们会在最快的时间解决。

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

往期文章

相关推荐
开开心心就好19 小时前
批量提取PDF中的图片,直接导出原图
前端·javascript·支持向量机·智能手机·pdf·html·启发式算法
比兔代理1 天前
正向代理与反向代理技术辨析,为什么代理 IP 属于正向代理
服务器·网络·http·ip
默_笙1 天前
🏛 给 AI 配一间办公室:Harness Engineering 六大模块与它的实现
前端·javascript
linux_cfan1 天前
videojs v10 源代码系列解读:14 · 谓词守卫:在运行时安全地调用能力
前端·javascript·音视频
天若有情6731 天前
【纯前端小工具】公历生日转农历,批量查询每年农历生日对应的公历日期(GitHub Pages在线直接用)
前端·javascript·github pages·农历转换·lunisolar·网页小工具
林语琛1 天前
我写的 switch…break 被 Babel 偷偷吞了
前端·javascript·babel
liuchangng1 天前
Jev 模型研究:从生成式大模型到决策式模型——System One、RLCD 校准与采用边界
java·javascript·人工智能·python·深度学习
我命由我123451 天前
CSS - CSS 媒体查询 orientation
前端·javascript·css·html·css3·html5·js
志尊宝1 天前
Vue3 零基础每日笔记(048):嵌套路由与命名视图——后台管理系统布局雏形
前端·javascript·vue.js·笔记·html5
@tangguo1231 天前
npm 和 yarn 配置说明
前端·javascript·npm·node.js·yarn