Files
bishe-STM32/docs/05_项目审查问题清单.md
T
2026-05-01 21:34:10 +08:00

345 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 项目审查问题清单
审查日期:2026-05-01
本文档用于记录当前项目中已发现的高风险问题,并作为后续逐项修复的跟踪清单。状态说明:
- `待处理`:尚未开始修复。
- `处理中`:已经开始改动或验证。
- `已修复`:代码已修复并通过基本验证。
- `暂缓`:因演示环境、硬件依赖或其他原因暂不处理。
## 1. 优先级概览
| 编号 | 优先级 | 状态 | 模块 | 问题 |
| --- | --- | --- | --- | --- |
| R-001 | P0 | 已修复 | 服务端 | 公网接口无鉴权且允许任意来源 |
| R-002 | P0 | 部分修复 | 全项目 | 明文密钥和凭据已进入项目文件 |
| R-003 | P1 | 已修复 | 服务端 | `face_id` 可造成路径穿越写读删文件 |
| R-004 | P1 | 已修复 | 服务端 | 大请求体会被静默截断 |
| R-005 | P1 | 已修复 | 服务端 / Qt | CSV/JSON 没有转义会破坏数据和响应 |
| R-006 | P1 | 已修复 | STM32 固件 | `sscanf` 未限制宽度,UART 输入可溢出栈缓冲 |
| R-007 | P2 | 已修复 | 服务端 | 多个 `std::stoi` 可被非法参数打崩服务线程 |
| R-008 | P2 | 已修复 | Qt 管理端 | 删除人脸 URL 未编码 |
| R-009 | P1 | 已修复 | STM32 固件 | NTP-only 模式下时间不会前进 |
| R-010 | P1 | 已修复 | STM32 固件 | 发送成功判断过早,可能静默丢签到 |
| R-011 | P1 | 已修复 | STM32 固件 | 今日缓存不区分时段,会误判重复签到 |
| R-012 | P1 | 已修复 | 服务端 | 签到请求手写 JSON 解析会被特殊字符破坏 |
| R-013 | P2 | 已修复 | K210 识别端 | 从 SD 卡加载特征时使用 `eval` |
| R-014 | P2 | 已修复 | 文档 | 总文档指向不存在的 Qt 工程文件 |
| R-015 | P2 | 已修复 | 服务端 / 数据 | 数据库缺少自动备份与恢复流程 |
| R-016 | P2 | 已修复 | 服务端 / K210 | 删除任务缺少 task_id 和状态跟踪 |
| R-017 | P2 | 已修复 | 服务端 / 多端同步 | 设备同步状态不可追踪 |
| R-018 | P2 | 已修复 | 部署 / 安全 | 公网 HTTP 明文传输缺少 HTTPS 或反向代理保护 |
| R-019 | P3 | 已修复 | 测试 | 关键接口缺少自动化回归脚本 |
| R-020 | P1 | 已修复 | K210 / 同步 | 删除 ACK 失败后本地版本仍前进,可能卡住删除任务 |
| R-021 | P2 | 已修复 | STM32 固件 / 多设备 | 多设备或缓存过期时重复签到仍可能漏判 |
| R-022 | P2 | 已修复 | STM32 固件 / ESP8266 | HTTP GET 可能接受半截响应 |
## 2. 详细问题
### R-001 公网接口无鉴权且允许任意来源
- 优先级:P0
- 状态:已修复
- 位置:`server/server_encrypted.cpp:1666`
- 影响:服务端暴露清空记录、删除人脸、上传映射、上传照片等写操作,但没有鉴权;响应固定允许任意跨域来源。只要端口可访问,外部请求就可能改写或删除考勤数据。
- 建议处理:
1. 给所有写接口增加 API Token 或签名校验。
2. 按部署环境限制 CORS 来源,不再使用通配符。
3. 公网部署时使用 HTTPS 和反向代理鉴权。
4. 将管理类接口与设备上传接口区分权限。
- 本次处理:主服务端 `server/server_encrypted.cpp` 已增加 `X-Api-Token` 校验,健康检查和 OPTIONS 预检除外;CORS 来源改为 `ATTENDANCE_CORS_ORIGIN` 配置,默认仅本地来源。Qt、STM32、K210 请求均已补 `X-Api-Token`。
### R-002 明文密钥和凭据已进入项目文件
- 优先级:P0
- 状态:部分修复
- 位置:`k210/main.py:34`、`User/main.c:23`、`QT/qml/Main.qml:2725`、`server/attendance.log`
- 影响:项目文件中包含 WiFi 密码、公网服务地址、固定 AES Key/IV、查看账号密码、日志中的疑似 API Key 等敏感信息。泄露后即使代码修复,旧凭据仍可能被继续使用。
- 建议处理:
1. 立即轮换已暴露的 WiFi 密码、API Key、演示账号密码和 AES Key/IV。
2. 将服务地址、WiFi、Token 等改为外部配置文件或烧录参数。
3. 日志输出中屏蔽敏感请求头。
4. 清理已有日志文件中的敏感内容。
- 本次处理:主链路代码和文档中的 WiFi 密码、公网地址改为占位配置;Qt 关于页移除固定演示账号密码;日志中的疑似 API Key 已脱敏;Qt 默认服务地址改为本机地址。仍需在真实环境中轮换已暴露的 WiFi、API Key、演示账号和 AES Key/IV。
### R-003 `face_id` 可造成路径穿越写读删文件
- 优先级:P1
- 状态:已修复
- 位置:`server/server_encrypted.cpp:837`
- 影响:`face_id` 直接来自 URL 并拼接成 `faces/<face_id>.jpg`,用于写入、读取和删除。包含路径分隔符或 `..` 时,可能越过 `faces` 目录操作其他文件。
- 建议处理:
1. 增加 `face_id` 白名单校验,只允许数字、字母、下划线、短横线等明确字符。
2. 对最终路径做规范化检查,确认仍位于 `faces` 目录下。
3. 所有照片读写删入口共用同一个安全路径构造函数。
- 本次处理:主服务端已增加 `isSafeId` 与 `buildFacePhotoPath`,照片读写删和重命名路径统一走安全 ID 校验。
### R-004 大请求体会被静默截断
- 优先级:P1
- 状态:已修复
- 位置:`server/server_encrypted.cpp:1228`
- 影响:读取 POST body 时,如果剩余数据超过约 40KB,循环不会继续读取,导致照片或配置内容被截断。K210 JPEG 上传很容易触发该问题。
- 建议处理:
1. 按 `Content-Length` 循环读取完整 body。
2. 设置明确最大请求大小,例如照片接口单独允许更大上限。
3. 超限时返回 HTTP 413。
4. 对读取不足的请求返回 400,不保存半截文件。
- 本次处理:主服务端按 `Content-Length` 读取完整请求体,普通 JSON 请求限制 64KB,照片请求限制 512KB,超限返回 413,读取不足返回 400。
### R-005 CSV/JSON 没有转义会破坏数据和响应
- 优先级:P1
- 状态:已修复
- 位置:`server/server_encrypted.cpp:459`、`QT/src/AppController.cpp:284`、`QT/src/AppController.cpp:317`
- 影响:签到记录直接用逗号拼 CSV,读取时也直接按逗号拆,再手写 JSON 字符串。姓名、状态、班级等字段包含逗号、引号、换行或反斜杠时,会导致 CSV 列错位、JSON 非法或 Qt 解析失败。
- 建议处理:
1. 服务端增加 CSV 字段转义和解析函数。
2. 服务端 JSON 响应统一经过 JSON 转义函数。
3. Qt 导出 CSV 时对每个字段做标准 CSV 转义。
4. 使用 SQLite 替代 CSV/多 JSON 文件,减少数据状态不一致。
- 本次处理:主服务端增加 CSV 解析/转义和 JSON 转义;Qt 导出 CSV 已对字段做标准转义;后端主存储已迁移到 `attendance.db`,旧 CSV/JSON 仅作为首次导入来源。
### R-006 `sscanf` 未限制宽度,UART 输入可溢出栈缓冲
- 优先级:P1
- 状态:已修复
- 位置:`Hardware/K210_USART.c:80`
- 影响:`%[^,]` 没有宽度限制,但目标缓冲只有 `id[20]` 和 `name[32]`。串口收到异常长字段时可能覆盖栈内存,造成固件异常。
- 建议处理:
1. 将格式改为 `%19[^,]`、`%31[^,]`。
2. 对接收缓冲做最大帧长、换行结束符和字段合法性校验。
3. 异常帧直接丢弃并清空缓冲。
- 本次处理:`Hardware/K210_USART.c` 和示例文件中的 `sscanf` 已增加字段宽度限制。
### R-007 多个 `std::stoi` 可被非法参数打崩服务线程
- 优先级:P2
- 状态:已修复
- 位置:`server/server_encrypted.cpp:1310`
- 影响:`limit`、`offset`、时间段参数直接调用 `std::stoi`,没有异常捕获和范围校验。非法请求参数可能让请求处理线程异常终止。
- 建议处理:
1. 增加安全整数解析函数。
2. 参数非法时返回 400。
3. 限制 `limit`、`offset` 和时间范围。
4. 所有 URL 参数统一走校验函数。
- 本次处理:主服务端已增加安全整数和时间解析,`limit`、`offset`、时间段和记录时间解析不再直接裸用 `std::stoi`。
### R-008 删除人脸 URL 未编码
- 优先级:P2
- 状态:已修复
- 位置:`QT/src/ApiClient.cpp:453`
- 影响:Qt 端删除人脸时直接把 `studentId` 拼进路径。如果学号包含空格、`#`、`?`、`/` 或中文,URL 会被截断或路由错乱。
- 建议处理:
1. 使用 `QUrl::toPercentEncoding` 编码路径段。
2. 服务端接收后进行 URL 解码和 ID 校验。
3. 为删除人脸接口补充异常 ID 的测试用例。
- 本次处理:Qt 删除人脸路径段已使用 `QUrl::toPercentEncoding` 编码。
### R-009 NTP-only 模式下时间不会前进
- 优先级:P1
- 状态:已修复
- 位置:`User/main.c:467-472`
- 影响:DS1302 不可用时,系统每秒只是把 `g_current_time.hour/minute` 再写入考勤模块,没有按系统 tick 推进秒、分钟和日期。同步一次 NTP 后,考勤时间会冻结在同步瞬间,后续时段判断可能长期错误。
- 建议处理:
1. 在 NTP-only 模式下基于 `Get_Time_ms()` 维护软件时钟。
2. 每秒递增 `g_current_time`,正确处理分钟、小时、日期进位。
3. NTP 同步成功时重置软件时钟基准。
4. 增加跨分钟、跨小时、跨天的基本验证。
- 本次处理:`User/main.c` 增加软件时钟推进逻辑,DS1302 不可用时按 `Get_Time_ms()` 每秒递增秒、分钟、小时和日期;NTP 同步成功后重置推进基准。
### R-010 发送成功判断过早,可能静默丢签到
- 优先级:P1
- 状态:已修复
- 位置:`Hardware/esp8266.c:230-236`
- 影响:STM32 侧 POST 只等待 ESP8266 的 `>` 提示并写出 HTTP 字符串,随后立即返回成功;没有等待 `SEND OK`,也没有检查服务端 HTTP 200 或 JSON `success`。网络中断、服务端 401/500、请求体未落库时,调用方仍可能把记录标记为已同步,造成静默丢签到。
- 建议处理:
1. 发送后等待 `SEND OK`,失败时返回 `ESP8266_FAIL`。
2. 继续读取 HTTP 响应,确认状态码为 200 且响应体包含成功标志。
3. 超时、401、500、响应解析失败都应保留记录为待同步或失败待重试。
4. 记录服务端返回的错误信息,便于联调排查 Token、加密和数据库问题。
- 本次处理:`Hardware/esp8266.c` 的加密 POST 发送后会等待 `SEND OK`、HTTP 200 和响应体 `success:true`;超时、发送失败、401/400/413/500 或 `success:false` 都返回失败,使记录保留为待重试。
### R-011 今日缓存不区分时段,会误判重复签到
- 优先级:P1
- 状态:已修复
- 位置:`Hardware/Attendance.c:75-108`
- 影响:当前缓存只保存 `student_id`,不保存考勤时段。任一时段签到成功后都会进入缓存,后续中午、下午、晚上时段再签到可能被 `Attendance_IsDuplicateInCache` 判为重复。开机不在时段时还会按 `00:00-23:59` 拉取全天记录,误判范围更大。
- 建议处理:
1. 缓存项增加时段编号或 `slot_start/slot_end` 字段。
2. 本地新增签到写缓存时同时写入当前时段。
3. 服务器下载今日记录时只填充当前有效时段的缓存;不在时段内不要拉取全天缓存用于查重。
4. 切换时段时清理或重建缓存,避免跨时段污染。
- 本次处理:`Hardware/Attendance.c` 的缓存项增加时段绑定;新增签到和服务器下载缓存都写入当前时段;不在时段内不再拉取全天缓存;时段切换时自动清空缓存。
### R-012 签到请求手写 JSON 解析会被特殊字符破坏
- 优先级:P1
- 状态:已修复
- 位置:`server/server_encrypted.cpp:707-742`
- 影响:`parseJSON` 直接按逗号拆字段、按第一个冒号拆键值,无法正确处理字符串里的逗号、冒号、反斜杠和转义引号。签到姓名、状态或后续字段一旦包含这些字符,会解析错列甚至写入错误数据。
- 建议处理:
1. 引入 `nlohmann/json` 等成熟 JSON 库,优先替换签到请求体解析。
2. 对必填字段做类型、长度和取值校验。
3. JSON 解析失败时返回 400,避免写入半解析数据。
4. 增加包含逗号、冒号、引号和反斜杠的解析测试样例。
- 本次处理:`server/server_encrypted.cpp` 的签到 JSON 解析改为逐字符解析字符串字面量,支持逗号、冒号、反斜杠和转义引号;签到字段增加 ID、长度、置信度范围和状态取值校验,非法请求返回 400。
### R-013 K210 从 SD 卡加载特征时使用 `eval`
- 优先级:P2
- 状态:已修复
- 位置:`k210/main.py:1315-1321`
- 影响:`recordftr.txt` 内容来自可写 SD 卡,`eval(parts[1])` 会执行任意 Python 表达式。文件损坏或被替换时,可能执行意外代码、卡死或耗尽内存。
- 建议处理:
1. 如果 MaixPy 支持,改用 `ast.literal_eval`。
2. 如果不支持,改为明确的浮点数组解析器,只接受数字、逗号、方括号和空白。
3. 校验特征向量长度和数值范围,异常记录跳过并打印错误。
4. 保存特征时考虑使用更容易校验的 JSON 或二进制格式。
- 本次处理:`k210/main.py` 已用 `parse_feature_vector` 替换 `eval`,只接受浮点数组允许字符,并校验向量长度,异常记录会被跳过并打印解析错误。
### R-014 总文档指向不存在的 Qt 工程文件
- 优先级:P2
- 状态:已修复
- 位置:`docs/00_项目总文档.md:15`
- 影响:总文档写的是用 `QT/AttendanceViewer.pro` 构建,但仓库里没有该文件;实际 Qt 项目使用 `QT/CMakeLists.txt`。部署、答辩复现或新成员接手时会被误导。
- 建议处理:
1. 将总文档中的 Qt 构建入口改为 `QT/CMakeLists.txt`。
2. 与 `docs/04_Qt管理端文档.md` 保持一致,说明当前推荐 CMake 构建。
3. 全仓库搜索旧 `.pro`、`qmake` 和旧接口路径,清理过时说明。
- 本次处理:总文档中的 Qt 构建入口已改为 `QT/CMakeLists.txt`;删除 `docs/07_后续优化路线.md` 前同步清理了相关引用。
### R-015 数据库缺少自动备份与恢复流程
- 优先级:P2
- 状态:已修复
- 位置:`server/server_encrypted.cpp`、`docs/03_服务端文档.md`
- 影响:当前服务端使用 `attendance.db` 作为主存储,但没有自动备份、恢复步骤和误删后的应急流程。调试、答辩演示或清空记录接口误操作时,可能导致考勤记录、映射和同步状态难以恢复。
- 建议处理:
1. 增加服务端启动前或每日首次启动的 SQLite 备份逻辑。
2. 在服务端文档中补充停止服务、备份、恢复和校验步骤。
3. Qt 端后续可增加导出数据库备份入口。
4. 备份文件应带日期时间后缀,避免覆盖最近可用备份。
- 本次处理:服务端启动时会把已有 `attendance.db` 复制到 `backups/attendance_YYYY-MM-DD_HH-MM-SS.db`,备份失败则停止启动;`docs/03_服务端文档.md` 已补恢复和校验流程。
### R-016 删除任务缺少 task_id 和状态跟踪
- 优先级:P2
- 状态:已修复
- 位置:`server/server_encrypted.cpp`、`k210/main.py`
- 影响:当前待删除任务主要按 `face_id` 列表流转,K210 删除成功后按 ID ACK。重复删除、删除后重新添加同 ID、多设备并发同步时,可能难以区分旧任务和新任务,也不方便追踪任务创建、下发、确认和失败状态。
- 建议处理:
1. 将删除任务升级为带 `task_id`、`face_id`、`student_id`、`created_at`、`status`、`ack_at` 的记录。
2. K210 ACK 时回传 `task_id`,服务端按任务确认。
3. 保留兼容旧 `face_id` ACK 的过渡逻辑,避免一次性破坏现有联调链路。
4. 在 Qt 或服务端状态接口中暴露待删除任务数量和最近任务状态。
- 本次处理:服务端 `pending_delete` 升级为任务表,包含 `task_id`、`face_id`、`student_id`、`created_at`、`status`、`ack_at`;同步响应同时返回兼容旧数组和 `delete_tasks`;K210 ACK 会回传 `task_ids`,服务端仍兼容旧 `face_id` 确认。
### R-017 设备同步状态不可追踪
- 优先级:P2
- 状态:已修复
- 位置:`server/server_encrypted.cpp`
- 影响:各端只在本地保存自己的 `last_version`,服务端不知道 STM32、K210、Qt 最后看到或确认到了哪个同步版本。设备长期离线、同步卡住、版本落后时,只能靠日志和现场排查,联调成本较高。
- 建议处理:
1. 增加 `device_sync_state` 表,记录 `client`、`last_seen_version`、`last_ack_version`、`last_seen_at`。
2. 在 `/api/v1/sync/state` 和 `/api/v1/sync/ack` 中更新设备状态。
3. 在 `/api/v1/system/storage` 中返回设备同步摘要。
4. 后续 Qt 可展示同步状态,但不要求作为首阶段必须项。
- 本次处理:服务端新增 `device_sync_state` 表;`/api/v1/sync/state` 记录设备最近看到的服务端版本,`/api/v1/sync/ack` 记录 ACK 版本;`/api/v1/system/storage` 返回 `device_sync_state` 摘要。
### R-018 公网 HTTP 明文传输缺少 HTTPS 或反向代理保护
- 优先级:P2
- 状态:已修复
- 位置:`server/server_encrypted.cpp`、部署配置
- 影响:服务端当前直接提供 HTTP 8082。若部署在公网,`X-Api-Token`、配置接口、照片上传下载和管理操作都会以明文传输,Token 可能被窃听或重放。AES 签到正文只覆盖 STM32 上传内容,不能保护管理 API 和设备同步 API。
- 建议处理:
1. 公网部署时使用 Nginx/Caddy 等反向代理终止 HTTPS。
2. 服务端尽量只监听本机或内网地址,由反向代理对外暴露。
3. 配置 HTTPS 后轮换 API Token 和相关密钥。
4. 文档中明确本机演示和公网部署的不同安全要求。
- 本次处理:服务端增加 `ATTENDANCE_BIND_HOST` 监听地址配置;文档新增公网部署安全要求,建议服务端绑定 `127.0.0.1` 并通过 Nginx/Caddy 终止 HTTPS 后再对外暴露。
### R-019 关键接口缺少自动化回归脚本
- 优先级:P3
- 状态:已修复
- 位置:`docs/06_后端接口Windows测试命令.md`、待新增测试脚本
- 影响:当前主要依赖手动 curl 文档验证接口。服务端、Qt、STM32、K210 协议经常一起变动,缺少脚本化回归会让鉴权、同步状态、时间段配置、照片接口和记录接口的破坏更晚被发现。
- 建议处理:
1. 保留现有手动 curl 文档,同时增加 PowerShell 自动化测试脚本。
2. 覆盖 health、storage、records、statistics、time-slots、sync/state、faces/photos 等低风险接口。
3. 对需要真实硬件或真实 AES 正文的接口保留手动验证说明。
4. 在每次服务端改动后运行脚本,记录测试结果。
- 本次处理:新增 `server/regression_api_tests.ps1`,覆盖 health、storage、time、sync、records、statistics、time-slots、duplicates、today、mappings、faces 等低风险接口;手动命令文档已加入脚本使用方式。
### R-020 删除 ACK 失败后本地版本仍前进,可能卡住删除任务
- 优先级:P1
- 状态:已修复
- 位置:`k210/main.py:1227-1239`
- 影响:K210 删除本地人脸后会向服务端发送同步 ACK,但当前没有判断 ACK 响应是否成功,就保存了 `server_version`。如果 ACK 请求丢包、超时或服务端未确认,服务端仍保留待删除任务;K210 下一次用已推进的 `last_version` 请求同步时可能得到 `changed:false`,导致该删除任务长期留在服务端,后续同步状态不一致。
- 建议处理:
1. 检查 `ack_resp` 是否包含成功标志,例如 `"success":true`。
2. 只有删除成功且 ACK 成功时,才保存新的 `sync_last_version`。
3. ACK 失败时保留旧版本,并打印日志,等待下一轮同步重试。
4. 可在服务端状态接口或 Qt 端观察 pending delete 数量,验证任务不会卡住。
- 备注:这是联调稳定性问题,不属于必须复杂化同步协议的工业级需求;毕业设计中用简单 ACK 成功判断即可。
- 本次处理:`k210/main.py` 在删除任务 ACK 后检查响应中是否包含 `"success":true`;ACK 失败时将本轮同步标记为失败,不保存新的本地同步版本,等待下一轮继续重试。
### R-021 多设备或缓存过期时重复签到仍可能漏判
- 优先级:P2
- 状态:已修复
- 位置:`Hardware/Attendance.c:520-529`
- 影响:当前签到处理主要检查 STM32 本地记录和开机/重连时下载的今日缓存。`Attendance_IsDuplicateOnServer` 已存在,但没有接入主签到路径。如果现场只有一台设备演示,影响较小;如果多台设备同时使用,或设备启动后缓存长时间未刷新,服务端已有的同一时段签到记录可能不会被当前设备发现,导致重复签到。
- 建议处理:
1. 在 `g_server_connected` 为真时,签到前调用一次 `Attendance_IsDuplicateOnServer`。
2. 查询失败时仍允许本地签到并进入待同步队列,避免弱网影响正常演示。
3. 时段切换、服务器重连成功后刷新今日记录缓存。
4. 如果只保留单设备演示,也应在论文或文档中说明本地缓存查重的适用范围。
- 备注:毕业设计阶段不需要做复杂分布式一致性,优先保证演示环境下行为可解释。
- 本次处理:`Hardware/Attendance.c` 在本地记录和缓存查重之后,服务器在线时调用 `Attendance_IsDuplicateOnServer` 做一次服务端查重;查询失败仍按未重复处理,避免弱网阻断演示。`User/main.c` 在 WiFi/HTTP 服务端重连成功后刷新时间段配置和今日记录缓存。
### R-022 HTTP GET 可能接受半截响应
- 优先级:P2
- 状态:已修复
- 位置:`Hardware/esp8266.c:486-498`
- 影响:`ESP8266_HttpGet` 在发现响应体后,如果超过约 3 秒且 `body_len > 0`,即使存在 `Content-Length` 且尚未收完整,也会复制响应并返回成功。弱网、ESP8266 分包或服务端响应稍慢时,STM32 可能拿到半截 JSON,进而导致时间段配置、同步状态或今日记录解析失败。
- 建议处理:
1. 如果响应头包含 `Content-Length`,必须等到 `body_len >= content_length` 才返回成功。
2. 只有没有 `Content-Length` 时,才使用“超时且已有响应体”的兜底逻辑。
3. 超时未收完整时返回 `ESP8266_FAIL`,让上层保留当前配置并下次重试。
4. 用较大的同步状态响应或人工延迟响应测试 ESP8266 分包场景。
- 备注:该项主要提升弱网稳定性,不影响当前本地小数据量演示的主体功能。
- 本次处理:`Hardware/esp8266.c` 的 GET 响应处理改为:只在没有 `Content-Length` 时使用“超时且已有响应体”的兜底逻辑;如果服务端返回了 `Content-Length`,必须等到响应体长度达到声明长度才返回成功。
## 3. 建议修复顺序
1. 已完成 R-020:K210 删除 ACK 失败时不再推进本地同步版本,避免服务端待删除任务卡住。
2. 已完成 R-022:ESP8266 GET 在有 `Content-Length` 时必须收完整响应,减少弱网下配置同步解析失败。
3. 已完成 R-021:STM32 在线签到前补服务端查重,重连后刷新今日记录缓存。
4. R-002 仍需真实环境人工轮换已暴露凭据;代码层面已尽量外部配置化和脱敏。
5. 已修复项保持回归关注:R-001、R-003、R-004、R-005、R-006、R-007、R-008、R-009 至 R-022。
## 4. 验证记录
- `k210/main.py`、`k210/view_attendance.py` 已通过普通 Python 语法检查;MaixPy 运行时仍需上板验证。
- `server/server_encrypted.cpp` 因当前本机缺少 OpenSSL 头文件,未完成语法编译验证。
- 现有 Keil 构建日志显示固件旧构建为 `0 Error(s), 0 Warning(s)`,但尚未在本次审查中重新编译固件。
- 2026-05-01:已完成主链路安全修复;旧版备用服务端与测试脚本已清理,避免误部署非鉴权接口。
- 2026-05-01:追加记录 R-009 至 R-014,作为后续优化和修复跟踪项。
- 2026-05-01:分析并合并 `docs/07_后续优化路线.md` 中仍需跟踪的项目,追加 R-015 至 R-019;同步删除该路线文档。
- 2026-05-01:完成 R-009 至 R-013、R-015 至 R-019 的代码和文档修复;新增服务端回归脚本 `server/regression_api_tests.ps1`。仍需上板验证 STM32/K210 运行时行为,并在真实部署中轮换 R-002 涉及的凭据。
- 2026-05-01:追加记录 R-020 至 R-022,作为后续优化跟踪项。
- 2026-05-01:完成 R-020 至 R-022 的代码修复;`k210/main.py` 已通过普通 Python 语法检查,STM32 相关改动仍需 Keil 编译和上板验证。