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

如何使用Mongoose创建倒计时,计时结束触发函数实现测验页自动登出?

基于Node.js + Mongoose的测验倒计时自动登出实现方案

整体采用服务端逻辑兜底+前端倒计时展示的方案,避免前端篡改时间绕过登出限制,核心逻辑如下:


1. 定义测验会话Mongoose Schema

首先创建测验会话集合,存储用户的测验开始时间、时长、活跃状态等核心数据,借助MongoDB的时间计算能力判断是否到期:

const mongoose = require('mongoose');

const QuizSessionSchema = new mongoose.Schema({
  userId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true
  },
  quizId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Quiz',
    required: true
  },
  // 服务端生成开始时间,禁止前端传入避免篡改
  startTime: {
    type: Date,
    default: Date.now
  },
  // 测验总时长,单位:分钟
  durationMinutes: {
    type: Number,
    required: true
  },
  isActive: {
    type: Boolean,
    default: true
  }
});

// 虚拟字段:自动计算会话过期时间,无需持久化存储
QuizSessionSchema.virtual('expireAt').get(function () {
  return new Date(this.startTime.getTime() + this.durationMinutes * 60 * 1000);
});

module.exports = mongoose.model('QuizSession', QuizSessionSchema);

2. 服务端定时触发到期登出逻辑

中小流量项目推荐用定时轮询方案,无需修改MongoDB配置,部署成本低:

  1. 先安装定时任务依赖:npm install node-cron
  2. 实现到期扫描和登出逻辑:
const cron = require('node-cron');
const QuizSession = require('./models/QuizSession');

// 初始化定时扫描任务,每分钟执行一次
function initQuizExpireMonitor() {
  cron.schedule('* * * * *', async () => {
    const currentTime = new Date();
    // 筛选所有已到期但仍标记为活跃的会话
    const expiredSessions = await QuizSession.find({
      isActive: true,
      $expr: {
        $lte: [
          { $add: ['$startTime', { $multiply: ['$durationMinutes', 60000] }] },
          currentTime
        ]
      }
    });

    // 批量处理到期会话
    for (const session of expiredSessions) {
      // 执行自定义登出逻辑:比如销毁测验权限、自动提交未完成答案、清除会话token等
      await customQuizLogoutLogic(session.userId, session.quizId);
      // 标记会话为已结束,避免重复处理
      session.isActive = false;
      await session.save();
    }
  });
}

// 替换为你的业务登出逻辑
async function customQuizLogoutLogic(userId, quizId) {
  console.log(`用户${userId}的测验${quizId}已到期,执行自动登出`);
  // 你的业务逻辑写在这里
}

// 项目启动时调用初始化方法
initQuizExpireMonitor();

如果需要秒级的触发精度,把定时任务的规则改为*/10 * * * * *即可每10秒扫描一次,可根据业务需求调整频率。


3. 前端配合实现自动跳转(可选)

服务端逻辑是兜底校验,前端可增加倒计时提升用户体验,到期自动触发页面跳转:

// 进入测验页时从服务端接口拉取剩余有效时长(单位:秒)
const remainingTime = await fetch('/api/quiz/get-remaining-time').then(res => res.json());

const countdownTimer = setInterval(() => {
  remainingTime--;
  if (remainingTime <= 0) {
    clearInterval(countdownTimer);
    // 调用登出接口后跳转到到期提示页
    fetch('/api/quiz/logout', { method: 'POST' }).then(() => {
      window.location.href = '/quiz/expired-notice';
    });
  }
}, 1000);

注意事项

  • 所有测验提交、页面访问请求,服务端都要校验会话的isActive状态,不能完全依赖前端判断
  • 测验开始时间必须由服务端生成,禁止接收前端传入的时间参数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 19:09:01