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

Vue2中Token续期定时器异常:页面切换不重置、提示仅触发一次

问题解决:Token续期定时器的修复方案

问题分析

原代码存在以下核心问题:

  • 定时器作用域错误:x和tokenTime在路由监听函数内定义,每次路由切换都会重新创建,无法正确复用和清除;且clearTimeout(tokenTime)属于错误用法——tokenTime是函数,并非定时器ID
  • 续期后未重启定时器:用户确认续期成功后,没有重新启动14分钟的提示定时器,导致后续不再触发续期询问
  • 路由切换逻辑混乱:缺少统一的定时器管理机制,切换页面时未正确初始化新的定时器
  • 倒计时实现错误:用setTimeout实现倒计时只会执行一次,无法持续更新剩余时间

修复后的完整代码

export default {
  data() {
    return {
      isActive: false,
      active: 'main',
      activeSidebar: false,
      userId: '',
      // 存储定时器ID,实现统一管理
      tokenRenewTimer: null, // 14分钟后触发续期提示的定时器
      countdownTimer: null, // 15分钟自动登出的倒计时定时器
      remainingTime: 900 // 15分钟=900秒
    };
  },

  methods: {
    logout() {
      console.log('Logout');
      this.clearAllTimers();
      this.$store.dispatch('authLogout');
      this.$store.commit('setLoginCheck', false);
      this.$router.push('/login');
    },

    // 清除所有定时器
    clearAllTimers() {
      if (this.tokenRenewTimer) {
        clearTimeout(this.tokenRenewTimer);
        this.tokenRenewTimer = null;
      }
      if (this.countdownTimer) {
        clearInterval(this.countdownTimer);
        this.countdownTimer = null;
      }
    },

    // 启动所有定时器
    startTokenTimers() {
      this.clearAllTimers(); // 先清除旧定时器,避免重复触发
      this.remainingTime = 900; // 重置倒计时

      // 14分钟后显示续期提示(14*60*1000=840000毫秒)
      this.tokenRenewTimer = setTimeout(() => {
        this.showRenewPrompt();
      }, 840000);

      // 启动15分钟自动登出的倒计时
      this.countdownTimer = setInterval(() => {
        this.remainingTime--;
        const min = Math.floor(this.remainingTime / 60);
        const sec = this.remainingTime % 60;
        document.getElementById('demo').innerHTML = `${min}分${sec}秒`;

        // 时间到自动登出
        if (this.remainingTime < 0) {
          this.clearAllTimers();
          document.getElementById('demo').innerHTML = '已超时';
          this.logout();
        }
      }, 1000);
    },

    // 显示Token续期提示
    async showRenewPrompt() {
      // 先检查当前Token状态
      await this.$store.dispatch('tokenCheck');
      const tokenData = this.$store.getters.tokenData;

      if (tokenData === 'N' || !tokenData) {
        alert('Token已失效');
        this.logout();
        return;
      }

      const confirmRenew = confirm('是否要延长Token有效期?');
      if (!confirmRenew) {
        alert('已取消Token续期');
        this.logout();
        return;
      }

      // 发起续期请求
      await this.$store.dispatch('tokenCheck');
      const newTokenData = this.$store.getters.tokenData;

      if (newTokenData === 'N' || !newTokenData) {
        alert('Token续期失败,已登出');
        this.logout();
      } else {
        alert('Token已成功续期');
        // 续期成功后重启定时器,确保下一次14分钟后再次提示
        this.startTokenTimers();
      }
    }
  },

  watch: {
    $route(to, from) {
      const loginCheck = this.$store.getters.loginCheck;
      const tokenData = this.$store.getters.tokenData;

      // 仅在登录状态且Token有效时启动定时器
      if (loginCheck && tokenData && tokenData !== 'N') {
        this.startTokenTimers();
      } else {
        this.clearAllTimers();
        alert('无有效Token,将跳转至登录页');
        this.logout();
      }
    }
  },

  // 页面初始化时启动定时器
  mounted() {
    const loginCheck = this.$store.getters.loginCheck;
    const tokenData = this.$store.getters.tokenData;
    if (loginCheck && tokenData && tokenData !== 'N') {
      this.startTokenTimers();
    }
  },

  // 页面销毁时清除定时器,避免内存泄漏
  beforeUnmount() {
    this.clearAllTimers();
  }
};

关键修复点说明

  1. 统一定时器管理:将定时器ID存储在组件data中,跨方法实现清除与复用,解决作用域问题
  2. 逻辑拆分独立:把定时器启动、清除、续期提示拆分为单独方法,代码结构更清晰,便于维护
  3. 路由切换重置定时器:路由变化时先清除旧定时器,再启动新定时器,解决切换页面未初始化的问题
  4. 续期后重启定时器:用户确认续期成功后,调用startTokenTimers()重新启动定时器,确保每14分钟触发一次续期提示
  5. 修复倒计时逻辑:用setInterval实现持续倒计时,替代原代码错误的setTimeout单次执行逻辑
  6. 生命周期优化:在mounted初始化定时器,beforeUnmount清除定时器,避免内存泄漏
  7. 异步逻辑优化:用async/await处理Token检查请求,确保获取最新Token状态后再进行业务判断

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 13:01:07