1. 项目概述与设计背景
线上考试系统作为教育信息化的重要组成部分,近年来在高校、培训机构和企业内部考核中发挥着越来越关键的作用。基于ThinkPHP/Laravel双框架的线上考试系统前台模块,正是针对传统纸质考试效率低下、组织成本高、数据分析困难等痛点设计的解决方案。
我在实际开发中发现,一套优秀的线上考试系统需要同时满足三个核心需求:首先是稳定性,考试过程中不能出现卡顿或数据丢失;其次是安全性,要防止作弊和数据泄露;最后是用户体验,界面要简洁直观,操作流程符合考生习惯。本系统采用PHP+MySQL技术栈,配合Vue.js前端框架,在保证性能的同时实现了良好的扩展性。
2. 技术架构解析
2.1 后端框架选型考量
系统同时支持ThinkPHP和Laravel两大PHP框架,这在架构设计上是个有趣的挑战。ThinkPHP以其"简单高效"的理念著称,特别适合快速开发中小型项目。而Laravel则提供了更优雅的语法和更完善的功能组件,适合构建复杂的业务逻辑。
我在数据库连接层做了抽象封装,通过配置切换即可兼容两种框架。关键代码如下:
php复制// 数据库适配器模式实现
class DBAdapter {
private $driver;
public function __construct($type) {
if($type == 'thinkphp') {
$this->driver = new ThinkPHP_Driver();
} else {
$this->driver = new Laravel_Driver();
}
}
public function query($sql) {
return $this->driver->execute($sql);
}
}
2.2 前端技术栈设计
采用Vue.js 2.x版本(考虑到学校机房浏览器兼容性)构建SPA应用,主要基于以下考虑:
- 组件化开发便于复用考试界面元素
- 响应式数据绑定简化了答题卡状态管理
- Vue Router实现无刷新页面跳转
特别值得注意的是,在低网速环境下我们实现了答案的本地缓存机制。当检测到网络异常时,系统会自动将答案暂存到localStorage,待网络恢复后再同步到服务器。
3. 核心功能实现细节
3.1 用户认证安全方案
登录模块采用多因素认证:
- 基础账号密码验证
- 短信验证码(集成阿里云SDK)
- 行为验证(滑动拼图)
为防止暴力破解,我在后端实现了基于Redis的登录失败计数器:
php复制// Laravel中间件示例
class ThrottleLogins {
public function handle($request, $next) {
$key = 'login_attempts:'.$request->ip();
if (Redis::get($key) >= 5) {
return response()->json(['error' => '尝试次数过多'], 429);
}
return $next($request);
}
}
3.2 考试过程关键技术
3.2.1 实时保存机制
通过WebSocket长连接+AJAX轮询双保险方案确保答案不丢失。具体实现:
- 每30秒自动保存一次
- 切换题目时立即保存
- 使用diff算法减少数据传输量
javascript复制// Vue组件中的答案保存逻辑
methods: {
saveAnswer: _.debounce(function() {
axios.post('/api/save', {
question_id: this.currentQuestion,
answer: this.selectedOption
}).catch(error => {
this.cacheToLocal(); // 失败时转存本地
});
}, 30000)
}
3.2.2 防作弊策略
- 全屏考试模式(使用Screenfull.js)
- 题目乱序+选项随机
- 行为监控:频繁切换标签页报警
- 前后摄像头监控(需用户授权)
4. 性能优化实践
4.1 数据库优化
针对考试系统读多写少的特点,做了以下优化:
- 试题表采用垂直分表:基础信息与内容分离
- 建立复合索引:
INDEX idx_exam_user (exam_id, user_id) - 查询缓存:高频访问的成绩数据Redis缓存
4.2 前端加载优化
- 代码分割:按路由懒加载组件
- 图片压缩:使用WebP格式
- CDN加速:静态资源托管
- 预加载关键资源:
<link rel="preload">
5. 典型问题排查实录
5.1 高并发下的死锁问题
在模拟考试高峰期测试时,发现当大量考生同时提交时会出现数据库死锁。通过分析发现是事务隔离级别设置不当导致。
解决方案:
php复制// 修改事务隔离级别
DB::transaction(function() {
DB::statement('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
// 业务逻辑
}, 3); // 重试3次
5.2 移动端兼容性问题
在部分Android设备上出现界面错位,排查发现是flex布局兼容性问题。最终采用以下方案:
- 增加autoprefixer配置
- 关键布局使用Grid作为fallback
- 针对低版本系统加载polyfill
6. 部署与运维建议
6.1 服务器配置
推荐的最低生产环境配置:
- CPU: 4核+
- 内存: 8GB+
- 带宽: 10Mbps+
- 系统: Ubuntu 20.04 LTS
6.2 监控方案
- 使用Prometheus监控服务器指标
- ELK收集日志
- 自定义健康检查接口:
php复制Route::get('/health', function() {
return response()->json([
'db' => DB::connection()->getPdo() ? 'ok' : 'fail',
'redis' => Redis::ping() ? 'ok' : 'fail'
]);
});
7. 扩展与定制开发
系统预留了多个扩展点:
- 插件系统:通过事件订阅机制
- API网关:方便对接第三方系统
- 主题引擎:支持自定义界面风格
对于需要深度定制的场景,建议从以下方面入手:
- 修改
config/custom.php中的配置项 - 扩展
App\Services下的服务类 - 重写
resources/views中的视图组件
在项目开发过程中,我特别总结了三点经验:首先是要做好异常情况的处理预案,考试系统对稳定性要求极高;其次是要重视日志记录,这是排查问题的关键;最后是测试要全面,不仅要测功能,还要模拟各种异常场景。