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

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

往期文章

相关推荐
秋雨凉人心3 小时前
简单发布一个npm包
前端·javascript·webpack·npm·node.js
哥谭居民00015 小时前
将一个组件的propName属性与父组件中的variable变量进行双向绑定的vue3(组件传值)
javascript·vue.js·typescript·npm·node.js·css3
踢足球的,程序猿5 小时前
Android native+html5的混合开发
javascript
前端没钱6 小时前
探索 ES6 基础:开启 JavaScript 新篇章
前端·javascript·es6
一条不想当淡水鱼的咸鱼7 小时前
taro中实现带有途径点的路径规划
javascript·react.js·taro
土豆炒马铃薯。7 小时前
【Vue】前端使用node.js对数据库直接进行CRUD操作
前端·javascript·vue.js·node.js·html5
DashVector8 小时前
如何通过HTTP API插入Doc
数据库·人工智能·http·阿里云·向量检索
DashVector8 小时前
如何通过HTTP API分组检索Doc
服务器·数据库·http·数据库开发·数据库架构
温轻舟8 小时前
前端开发 -- 自动回复机器人【附完整源码】
前端·javascript·css·机器人·html·交互·温轻舟
赵大仁8 小时前
深入解析 Vue 3 的核心原理
前端·javascript·vue.js·react.js·ecmascript