You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用Refresh Token自动更新JWT Access Token以维持有效访问

基于Quasar的Token静默刷新实现方案

一、最优触发时机选择

结合你的场景,**推荐「提前定时刷新 + 请求前校验兜底」**的组合策略,比单一方式更可靠:

  • 定时刷新:在Access Token过期前1-2分钟触发刷新(比如Token有效期10分钟,就在第8分钟发起请求)。这样能保证大部分场景下Token始终有效,避免每次请求都校验的冗余。
  • 请求前校验兜底:如果用户长时间闲置(比如15分钟后回到应用),定时任务可能因后台休眠停止,此时在每次API请求前先检查Access Token剩余有效期,若不足30秒,先静默刷新再发起业务请求。

页面切换时刷新的弊端:频繁切换页面会重复触发刷新,增加不必要的API调用,效率不如定时+请求兜底的组合。

二、静默刷新Token的具体实现

1. 核心逻辑封装

在Quasar中封装全局Token管理工具(比如src/utils/token.js),包含以下方法:

// 获取Access Token剩余有效期(秒)
export const getTokenRemainingTime = () => {
  const tokenInfo = JSON.parse(localStorage.getItem('tokenInfo')) || {};
  const expiresAt = tokenInfo.expiresAt; // 登录时需存储Token过期时间戳
  if (!expiresAt) return 0;
  return (expiresAt - Date.now()) / 1000;
};

// 静默刷新Token
export const refreshAccessToken = async () => {
  const refreshToken = localStorage.getItem('refreshToken');
  if (!refreshToken) throw new Error('无可用Refresh Token');
  
  // 调用后端刷新接口
  const res = await fetch('/api/auth/refresh', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ refreshToken })
  });
  
  const newTokenInfo = await res.json();
  // 更新本地存储的Token信息,记录新的过期时间戳
  localStorage.setItem('tokenInfo', JSON.stringify({
    accessToken: newTokenInfo.accessToken,
    expiresAt: Date.now() + 10 * 60 * 1000 // 10分钟有效期
  }));
  // 部分后端会返回新的Refresh Token,无则沿用旧的
  localStorage.setItem('refreshToken', newTokenInfo.refreshToken || refreshToken);
};

2. 定时任务与iOS后台唤醒处理

在src/boot目录下创建token-refresh.js,处理定时任务及iOS后台唤醒场景:

import { getTokenRemainingTime, refreshAccessToken } from 'src/utils/token';

export default async ({ app }) => {
  let refreshTimer = null;

  // 启动/重置定时刷新任务
  const startRefreshTimer = () => {
    if (refreshTimer) clearTimeout(refreshTimer);
    const remainingTime = getTokenRemainingTime();
    // 剩余时间大于2分钟则设置在剩余2分钟时刷新,否则立即刷新
    const delay = Math.max(remainingTime - 120, 0) * 1000;
    refreshTimer = setTimeout(async () => {
      try {
        await refreshAccessToken();
        startRefreshTimer(); // 刷新成功后重置定时任务
      } catch (err) {
        // 刷新失败跳转登录页(比如Refresh Token失效)
        app.router.push('/login');
      }
    }, delay);
  };

  // 应用启动时初始化定时任务(已登录状态)
  if (localStorage.getItem('tokenInfo')) {
    startRefreshTimer();
  }

  // 监听应用前后台切换,解决iOS后台唤醒后定时任务失效问题
  document.addEventListener('visibilitychange', () => {
    if (!document.hidden && localStorage.getItem('tokenInfo')) {
      const remainingTime = getTokenRemainingTime();
      // 剩余时间不足30秒立即刷新,否则重置定时任务
      if (remainingTime < 30) {
        refreshAccessToken().then(startRefreshTimer);
      } else {
        startRefreshTimer();
      }
    }
  });
};

随后在quasar.conf.js的boot数组中添加该文件,确保应用启动时加载。

3. 请求前校验兜底

在API请求拦截器(比如Axios)中添加Token校验逻辑:

import axios from 'axios';
import { getTokenRemainingTime, refreshAccessToken } from 'src/utils/token';

const api = axios.create({ baseURL: '/api' });

api.interceptors.request.use(async (config) => {
  const tokenInfo = JSON.parse(localStorage.getItem('tokenInfo')) || {};
  if (!tokenInfo.accessToken) {
    window.location.href = '/login';
    return Promise.reject(new Error('未登录'));
  }

  const remainingTime = getTokenRemainingTime();
  // Token剩余有效期不足30秒时,先刷新再发起请求
  if (remainingTime < 30) {
    try {
      await refreshAccessToken();
      const newTokenInfo = JSON.parse(localStorage.getItem('tokenInfo'));
      config.headers.Authorization = `Bearer ${newTokenInfo.accessToken}`;
    } catch (err) {
      window.location.href = '/login';
      return Promise.reject(err);
    }
  } else {
    config.headers.Authorization = `Bearer ${tokenInfo.accessToken}`;
  }

  return config;
});

export default api;

三、关于请求前刷新的频率问题

每次请求前都刷新确实会增加API调用量,但通过有效期阈值判断可避免不必要的刷新:仅当Token剩余时间不足30秒时才触发刷新,其他场景直接使用现有Token发起请求。这样既保证了请求有效性,又不会产生过多冗余的刷新请求。

内容的提问来源于stack exchange,提问作者kappxl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 23:20:37