首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >在线考试断网了答案会丢吗:以服务端时间为准的断点续答与到点强制交卷

在线考试断网了答案会丢吗:以服务端时间为准的断点续答与到点强制交卷

原创
作者头像
用户5598620
发布2026-09-16 09:00:24
发布2026-09-16 09:00:24
940
举报

在线测验、随堂考试、认证答题这类场景,对可靠性的要求比普通表单高得多:考生答到一半网络断了,答案不能丢;有人改电脑本地时间想拖延,系统不能被绕过;考试到点必须收卷,不能有人继续作答;网络抖动重试,也不能交上去两份。这篇给一套以服务端时间为唯一准绳的断点续答与强制交卷方案。

一、在线考试最容易出问题的四个环节

先把风险点摆清楚,方案逐条对应:

  • 答题过程:断网、闪退、误关页面,已作答内容丢失;
  • 时间控制:以考生设备时钟倒计时,改系统时间就能多答;
  • 收卷环节:到点后页面不锁定,仍可继续填写或晚交;
  • 交卷动作:弱网下用户连点提交,产生重复交卷或答案互相覆盖。

这些问题的共同根源是“把时间和状态的裁判权交给了不可信的客户端”。核心原则只有一句:时间以服务端为准,答案以服务端暂存为准,交卷以服务端状态为准,客户端只负责采集和展示。

二、为什么考试时间必须以服务端为准

考生设备的时钟可以随意修改,倒计时若纯靠本地时间计算,改一下系统时间就能延长作答。正确做法是:开考时由服务端下发本场考试的权威时间信息——服务器当前时间、开考时刻、截止时刻、剩余时长;进入答题后,客户端定期向服务端校时,用“服务端时间差”修正本地倒计时,而不是直接信任本机时钟:

代码语言:javascript
复制
// 记录服务端与本地的时间差,倒计时基于它修正
let serverOffset = 0;
async function syncServerTime() {
  const t0 = Date.now();
  const { serverNow, deadline } = await fetch("/exam/time?paperId=" + paperId).then(r => r.json());
  const t1 = Date.now();
  const rtt = t1 - t0;
  serverOffset = serverNow + Math.round(rtt / 2) - t1;   // 估算并抵消网络往返
  return { deadline, now: () => Date.now() + serverOffset };
}
// 是否到点,一律用修正后的时间判断
function remainSeconds(deadline) {
  return Math.max(0, Math.round((deadline - (Date.now() + serverOffset)) / 1000));
}

即使考生完全断网,也用最近一次校时得到的差值在本地估算,恢复网络后立即再校;是否真正截止,最终仍由服务端在每次接收答案和交卷时判定。

三、答案怎么暂存,断网才不会丢

可靠的答题过程采用“三层保存”:本地草稿、增量上报、服务端暂存。

  • 本地草稿:每作答一题就写入浏览器本地存储,闪退或误关后重进能立刻恢复;
  • 增量上报:答案变化做防抖后增量上报到服务端暂存表,带上题号和最后修改时间;
  • 服务端暂存:服务端保存每道题的最新答案和版本,这是换设备续答和最终收卷的依据。

服务端可用两张表承载,一场考试一条主记录、每题一条答案明细:

代码语言:sql
复制
CREATE TABLE exam_attempt (
  attempt_id   BIGINT PRIMARY KEY,
  paper_id     BIGINT NOT NULL,
  user_id      BIGINT NOT NULL,
  status       VARCHAR(16) NOT NULL,  -- IN_PROGRESS / SUBMITTED / AUTO_CLOSED
  start_at     DATETIME NOT NULL,
  deadline_at  DATETIME NOT NULL,
  submit_at    DATETIME,
  UNIQUE KEY uk_user_paper (paper_id, user_id)
);
CREATE TABLE exam_answer (
  attempt_id   BIGINT NOT NULL,
  question_id  BIGINT NOT NULL,
  answer_text  TEXT,
  version      INT NOT NULL,         -- 每次更新递增
  updated_at   DATETIME NOT NULL,
  PRIMARY KEY (attempt_id, question_id)
);

断网期间答案先积压在本地队列并标记“待同步”,网络恢复后按题号顺序补传;服务端按版本号决定是否覆盖,旧版本不覆盖新版本,避免乱序到达把新答案冲掉。换设备登录时,直接拉取服务端暂存的答案继续作答,做到断点续答。

四、到点强制交卷怎么做

到点收卷必须由服务端兜底,不能只靠考生页面上的倒计时。客户端倒计时只用于提前提醒(如剩余5分钟提示)和到点后立即锁定界面;真正的截止发生在服务端:超过截止时刻后,答案上报接口不再接收修改,交卷按已暂存的最后版本生成成绩;对于到点仍未主动交卷的尝试,由定时扫描把进行中的记录批量置为“自动收卷”:

IN_PROGRESS(作答中)→ SUBMITTED(主动交卷)或 AUTO_CLOSED(到点自动收卷),一旦进入终态,答案与成绩不再变更。

这样即使考生卡在断网状态、页面一直没关,恢复后也会发现本场已按服务端暂存内容收卷,无法拖延。

五、重复交卷怎么保证幂等

弱网下考生连点“交卷”,或客户端超时重试,都可能发出多个交卷请求。用“交卷令牌+状态机”解决:进入考试时服务端下发一个幂等令牌,交卷请求必须携带;服务端处理时先检查 attempt 状态,只有处于 IN_PROGRESS 才执行收卷并置为终态,已处于终态的重复请求不再重复处理,直接返回第一次的交卷结果。前端在发出交卷后立即把按钮置灰,配合服务端状态判断,双保险杜绝重复交卷和答案覆盖。

六、闪退、换设备、断网续答的边界处理

几个容易遗漏的边界要提前定规则:答题中途闪退,重进先读本地草稿、再和服务端暂存按版本合并;同一账号在另一台设备登录续答,以服务端暂存为准拉取,并把原设备会话置为失效,避免两端同时写;断网恢复补传时若本场已截止,只接受截止前最后一次有效暂存,超时改动不计;全程把关键动作(开考、每次暂存、交卷、自动收卷)记日志,便于争议时回溯。

七、踩坑清单

  • 用设备本地时间做倒计时,改系统时间即可延长作答——服务端下发并定期校时;
  • 答案只存内存或只存本地,清缓存、换设备就丢失——本地草稿加服务端暂存双保险;
  • 增量上报乱序到达,旧答案覆盖新答案——带版本号,旧不盖新;
  • 只靠前端到点锁页面,断网即可绕过——服务端截止加定时自动收卷;
  • 交卷接口不做幂等,连点产生重复记录——交卷令牌加状态机;
  • 多端同时作答互相覆盖——续答拉服务端暂存、旧会话失效。

八、工程落地建议

建议把在线考试能力抽象成独立服务,统一管理考试时间、作答暂存、交卷收卷三条主线:时间服务负责下发权威时刻与校时;作答服务负责增量暂存、版本合并与续答;收卷服务负责主动交卷、定时自动收卷和幂等。客户端尽量做薄,只承担采集、本地兜底和展示,所有裁决放在服务端。这套模型同样适用于问卷限时提交、在线测评、随堂练习等对时间和可靠性敏感的教育场景。

九、常见问题

Q:完全断网到考试结束,答案还能保留吗?

A:断网期间答案先存本地草稿,恢复网络后按版本补传到服务端;若恢复时已到截止时间,以服务端收到的截止前最后一次有效暂存为准收卷。

Q:到点自动收卷和主动交卷有区别吗?

A:结果都是形成终态成绩,区别只在来源:主动交卷由考生触发,自动收卷由服务端到点扫描触发,终态后都不再接受修改。

Q:怎么防止考生改本地时间?

A:不把本地时间作为依据,倒计时用服务端校时差值估算,能否作答和交卷一律由服务端按其时钟判定。

十、复盘清单

  • 考试时间是否由服务端下发、客户端定期校时?
  • 答案是否做到本地草稿、增量上报、服务端暂存三层保存?
  • 补传是否带版本号、避免乱序覆盖?
  • 到点是否由服务端截止并自动收卷,而非只锁前端?
  • 交卷是否用令牌加状态机保证幂等、终态不可改?

在线考试可靠与否,关键在于别把裁判权交给客户端:时间、答案、交卷都以服务端为准,客户端只做兜底采集。把校时、暂存续答、强制收卷和幂等这四件事做扎实,断网、闪退、改时间、重复交卷就都不会让一场考试失控。本文为后端工程实践分享,具体实现以业务规则为准。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、在线考试最容易出问题的四个环节
  • 二、为什么考试时间必须以服务端为准
  • 三、答案怎么暂存,断网才不会丢
  • 四、到点强制交卷怎么做
  • 五、重复交卷怎么保证幂等
  • 六、闪退、换设备、断网续答的边界处理
  • 七、踩坑清单
  • 八、工程落地建议
  • 九、常见问题
  • 十、复盘清单
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档