1. 项目背景与核心需求
卫生应急培训是提升公共卫生事件应对能力的关键环节,而传统的线下报名考试模式存在组织成本高、效率低、覆盖范围有限等问题。基于微信小程序的Python卫生应急培训报名考试系统,正是为了解决这些痛点而设计的轻量化解决方案。
微信小程序作为载体具有天然优势:
- 无需安装,即用即走
- 跨平台兼容(iOS/Android)
- 完善的用户体系(微信账号直接登录)
- 丰富的原生API(定位、支付、消息通知等)
Python在后端的应用则体现在:
- Django/Flask框架快速构建RESTful API
- 强大的数据处理能力(Pandas处理报名信息)
- 丰富的机器学习库(智能组卷算法)
- 成熟的异步任务框架(Celery处理考试提交)
实际开发中发现:微信小程序的顶部导航栏高度在不同机型上存在差异(iOS约44px,Android约48px),需要在app.json中通过"navigationStyle":"custom"自定义布局时特别注意适配问题。
2. 系统架构设计
2.1 技术栈选型
| 层级 | 技术方案 | 选型理由 |
|---|---|---|
| 前端 | 微信小程序 + UniApp | 跨端开发效率高,兼容微信原生API |
| 后端 | Python3.9 + Flask | 轻量灵活,适合快速迭代的中小型项目 |
| 数据库 | MySQL 8.0 + Redis | 事务型数据与缓存分离,Redis同时用作Celery消息队列 |
| 文件存储 | 微信云存储/自建MinIO | 根据预算选择,培训视频等大文件建议使用分片上传 |
| 部署 | Docker + Nginx | 容器化便于迁移,Nginx处理静态资源和负载均衡 |
2.2 核心模块划分
graph TD A[微信小程序] --> B(网络请求) B --> C[Python API] C --> D{路由分发} D --> E[用户模块] D --> F[报名模块] D --> G[考试模块] D --> H[证书模块] E --> I[(MySQL)] F --> I G --> J[(Redis)] H --> K[PDF生成](注:实际输出时应删除mermaid图表,此处仅为说明用)
3. 关键实现细节
3.1 微信端特殊问题处理
导航栏适配方案:
// 获取系统信息 const systemInfo = wx.getSystemInfoSync() const statusBarHeight = systemInfo.statusBarHeight const menuButtonInfo = wx.getMenuButtonBoundingClientRect() const navHeight = (menuButtonInfo.top - statusBarHeight) * 2 + menuButtonInfo.height Page({ data: { navHeight, statusBarHeight } })常见网络错误处理:
backgroundfetch privacy fail:需在app.json配置"requiredBackgroundModes": ["fetch"]media_err_network:视频URL必须配置download域名白名单- 文件上传失败:检查服务器是否返回正确的CORS头
3.2 Python后端核心代码
Flask路由示例:
from flask import request, jsonify from werkzeug.utils import secure_filename @app.route('/api/upload', methods=['POST']) def handle_upload(): if 'file' not in request.files: return jsonify(code=400, msg='No file part') file = request.files['file'] if file.filename == '': return jsonify(code=400, msg='No selected file') filename = secure_filename(file.filename) file.save(os.path.join(UPLOAD_FOLDER, filename)) return jsonify(code=200, url=f'/uploads/{filename}') # 考试提交异步处理 @celery.task def grade_exam(submission_id): from models import ExamSubmission submission = ExamSubmission.query.get(submission_id) # 阅卷逻辑...4. 数据库设计要点
4.1 主要表结构
用户表(users)
CREATE TABLE `users` ( `id` int NOT NULL AUTO_INCREMENT, `openid` varchar(32) NOT NULL COMMENT '微信唯一标识', `unionid` varchar(32) DEFAULT NULL, `mobile` varchar(20) DEFAULT NULL COMMENT '加密存储', `real_name` varchar(50) DEFAULT NULL, `id_number` varchar(50) DEFAULT NULL COMMENT '加密存储', `avatar` varchar(255) DEFAULT NULL, `last_login` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_openid` (`openid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;考试表(exams)
CREATE TABLE `exams` ( `id` int NOT NULL AUTO_INCREMENT, `title` varchar(100) NOT NULL, `start_time` datetime NOT NULL, `end_time` datetime NOT NULL, `duration` int NOT NULL COMMENT '分钟', `pass_score` int NOT NULL DEFAULT 60, `question_count` int NOT NULL, `status` tinyint NOT NULL DEFAULT 0 COMMENT '0未开始 1进行中 2已结束', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;5. 安全与性能优化
5.1 关键安全措施
数据传输安全:
- 所有API必须HTTPS
- 敏感字段(手机号、身份证)使用AES加密存储
- 微信小程序配置request合法域名
防作弊机制:
- 考试过程随机抓拍(使用wx.chooseMedia)
- 题目乱序+选项乱序
- 提交频率限制(同一用户10秒内只能提交一次)
接口防护:
- JWT身份验证
- 关键操作日志记录
- 短信验证码防刷(Redis计数)
5.2 性能优化实践
缓存策略示例:
from functools import wraps from flask import current_app def cache_response(timeout=300): def decorator(f): @wraps(f) def decorated_function(*args, **kwargs): cache_key = f"{request.path}{hash(frozenset(request.args.items()))}" data = current_app.redis.get(cache_key) if data is not None: return jsonify(json.loads(data)) resp = f(*args, **kwargs) current_app.redis.setex(cache_key, timeout, resp.get_data(as_text=True)) return resp return decorated_function return decorator @app.route('/api/exam/list') @cache_response(timeout=60) def exam_list(): # 数据库查询逻辑...6. 部署与运维
6.1 服务器配置建议
最低配置:
- 2核CPU
- 4GB内存
- 100GB SSD(根据培训视频数量调整)
推荐Docker部署:
FROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 5000 CMD ["gunicorn", "-w 4", "-b :5000", "app:app"]6.2 监控与日志
错误监控:
- 微信小程序错误通过
wx.onError收集 - Python端使用Sentry捕获异常
- 微信小程序错误通过
日志分级:
- access.log记录所有请求
- error.log记录WARNING以上级别日志
- 使用logrotate进行日志轮转
性能监控:
- Prometheus + Grafana监控接口响应时间
- 数据库慢查询日志定期分析
7. 典型问题排查
7.1 微信小程序真机调试问题
TextEncoder未定义问题:
// 在app.js中添加polyfill if (typeof TextEncoder === 'undefined') { const { TextEncoder, TextDecoder } = require('text-encoding') global.TextEncoder = TextEncoder global.TextDecoder = TextDecoder }iOS视频播放问题:
- 确认服务器支持Range请求
- 视频格式优先使用MP4(H.264编码)
- 检查response header包含:
Accept-Ranges: bytes Content-Type: video/mp4
7.2 Python环境问题
Anaconda环境warning处理:
# 激活环境时忽略警告 conda activate your_env 2>/dev/null依赖冲突解决:
# 使用pip-tools管理依赖 pip-compile requirements.in # 生成精确版本锁文件 pip-sync requirements.txt # 同步环境开发过程中发现,微信小程序在Android机型上调用wx.downloadFile时,如果URL包含特殊字符需要先进行encodeURIComponent处理,否则可能触发fail url not in domain list错误,即使该域名已在后台配置。这是微信基础库的一个已知问题,临时解决方案是在后端做302重定向。