更新文档
This commit is contained in:
+619
-114
@@ -1,152 +1,657 @@
|
||||
# 服务端文档
|
||||
|
||||
## 1. 推荐服务端版本
|
||||
当前项目推荐使用:`server/server_encrypted.cpp`
|
||||
## 1. 服务端的作用
|
||||
|
||||
原因:
|
||||
- 支持 STM32 上传加密签到数据。
|
||||
- 支持 Qt 管理端所需管理 API。
|
||||
- 支持 K210 人脸照片与映射同步相关 API。
|
||||
服务端是整个系统的数据中心。STM32、K210 和 Qt 管理端都通过 HTTP 与它通信。
|
||||
|
||||
## 2. 端口与数据文件
|
||||
- HTTP 端口:`8082`
|
||||
- SQLite 数据库:`attendance.db`
|
||||
- 启动备份目录:`backups/`
|
||||
- 日志:运行时生成 `attendance.log`
|
||||
- 旧数据迁移来源:`attendance_database.csv`、`timeslots_config.json`、`mapping_config.json`、`face_id_mapping.json`、`pending_delete.json`、`sync_request.json`、`sync_version.txt`
|
||||
- 人脸目录:`faces/`
|
||||
- 全局同步版本:存储在 `attendance.db` 的 `kv_store` 表中。
|
||||
- 删除任务:存储在 `pending_delete` 表中,包含 `task_id`、`face_id`、`student_id`、`created_at`、`status`、`ack_at`。
|
||||
- 设备同步状态:存储在 `device_sync_state` 表中,用于追踪各端最近同步版本和 ACK 版本。
|
||||
它负责:
|
||||
|
||||
## 3. 签到数据链路
|
||||
1. STM32 调用 `POST /api/v1/attendance/checkins` 上传 Base64 密文。
|
||||
2. 服务端按 AES-128-CBC 解密并解析 JSON。
|
||||
3. 将记录写入 `attendance.db` 的 `records` 表(含 `class_id` 字段)。
|
||||
1. 接收 STM32 加密上传的签到记录。
|
||||
2. 解密、校验并保存记录。
|
||||
3. 提供考勤记录和统计数据给 Qt。
|
||||
4. 保存签到时间段配置。
|
||||
5. 保存学生姓名映射和班级名称映射。
|
||||
6. 保存 K210 上传的人脸照片。
|
||||
7. 保存人脸 ID 到真实学号的映射。
|
||||
8. 维护待删除人脸任务。
|
||||
9. 维护全局同步版本号。
|
||||
10. 提供健康检查、存储状态和时间接口。
|
||||
|
||||
## 4. 核心 API(按模块)
|
||||
### 4.1 考勤与统计
|
||||
- `POST /api/v1/attendance/checkins`
|
||||
- `GET /api/v1/attendance/records?limit=&offset=`
|
||||
- `GET /api/v1/attendance/statistics`
|
||||
- `POST /api/v1/attendance/records/clear`
|
||||
- `DELETE /api/v1/attendance/records?timestamp=&student_id=`
|
||||
- `GET /api/v1/system/health`
|
||||
- `GET /api/v1/system/storage`
|
||||
- `GET /api/v1/system/time`
|
||||
当前推荐服务端文件:
|
||||
|
||||
说明:
|
||||
- `/api/v1/attendance/records` 与 `/api/v1/attendance/statistics` 默认返回明文 JSON;请求头包含 `X-Encrypted-Response: true` 时返回加密数据。
|
||||
```text
|
||||
server/server_encrypted.cpp
|
||||
```
|
||||
|
||||
### 4.2 时间段与查重
|
||||
- `POST /api/v1/config/time-slots`
|
||||
- `GET /api/v1/config/time-slots`
|
||||
- `GET /api/v1/attendance/duplicates?student_id=&slot_start=&slot_end=`
|
||||
- `GET /api/v1/attendance/today?slot_start=&slot_end=`
|
||||
## 2. 技术栈
|
||||
|
||||
### 4.3 映射与照片
|
||||
- `POST /api/v1/config/mappings`
|
||||
- `GET /api/v1/config/mappings`
|
||||
- `GET /api/v1/faces/photos`
|
||||
- `GET /api/v1/faces/photos/<id>`
|
||||
- `POST /api/v1/faces/photos/<face_id>`
|
||||
- `POST /api/v1/faces/mappings`
|
||||
- `GET /api/v1/faces/mappings`
|
||||
- `GET /api/v1/faces/student-ids`
|
||||
| 项 | 内容 |
|
||||
| --- | --- |
|
||||
| 语言 | C++ |
|
||||
| HTTP 实现 | 原生 socket + 每连接一个线程 |
|
||||
| 数据库 | SQLite |
|
||||
| 加密库 | OpenSSL EVP AES-128-CBC |
|
||||
| 图片存储 | 本地 `faces/*.jpg` |
|
||||
| 默认端口 | `8082` |
|
||||
| 默认数据库 | `attendance.db` |
|
||||
|
||||
### 4.4 统一同步接口(推荐)
|
||||
- `GET /api/v1/sync/state?client=<client>&last_version=<version>`
|
||||
- `POST /api/v1/sync/ack`
|
||||
- `GET /api/v1/sync/version`
|
||||
## 3. 运行时文件
|
||||
|
||||
说明:
|
||||
- 服务端是唯一权威状态源。
|
||||
- 每次签到、清空/删除记录、修改时间段、修改映射、上传照片、删除人脸,服务端都会递增 `kv_store.sync_version`。
|
||||
- 设备端保存自己的 `last_version`,请求时带给服务端。
|
||||
- 服务端会记录每个 `client` 的 `last_seen_version`、`last_ack_version` 和 `last_seen_at`,可通过 `/api/v1/system/storage` 查看。
|
||||
- 如果版本无变化,服务端返回 `changed:false`,设备端无需重复解析配置。
|
||||
- 如果版本有变化,服务端返回 `changed:true` 和当前客户端需要的状态。
|
||||
- `/api/v1/sync/version` 只返回当前版本和服务端时间,适合调试时快速确认同步版本。
|
||||
服务端启动后主要依赖当前工作目录下的文件。在哪个目录运行,就在哪个目录读写这些文件。
|
||||
|
||||
客户端示例:
|
||||
- `client=k210`:返回 `face_mappings` 和 `pending_delete`。
|
||||
- `client=stm32`:返回 `time_slots` 和 `server_time`。
|
||||
- `client=qt`:返回时间段、人脸映射、照片列表、学生ID列表、记录、统计和映射配置。
|
||||
- `client=all`:返回全部可同步状态。
|
||||
| 文件或目录 | 当前用途 |
|
||||
| --- | --- |
|
||||
| `attendance.db` | 主 SQLite 数据库 |
|
||||
| `faces/` | 人脸照片目录 |
|
||||
| `backups/` | 数据库备份目录 |
|
||||
| `attendance_database.csv` | 旧版 CSV 记录,首次初始化时可导入 |
|
||||
| `timeslots_config.json` | 旧版时间段配置,首次初始化时可导入 |
|
||||
| `mapping_config.json` | 旧版姓名/班级映射,首次初始化时可导入 |
|
||||
| `face_id_mapping.json` | 旧版人脸映射,首次初始化时可导入 |
|
||||
| `pending_delete.json` | 旧版待删除列表,首次初始化时可导入 |
|
||||
| `sync_request.json` | 旧版同步请求标志,首次初始化时可导入 |
|
||||
| `sync_version.txt` | 旧版同步版本号,首次初始化时可导入 |
|
||||
|
||||
K210 删除确认示例:
|
||||
首次启动时,如果 SQLite 表中没有数据,服务端会尝试从这些旧文件导入;导入后主要读写 SQLite。
|
||||
|
||||
## 4. SQLite 表结构
|
||||
|
||||
服务端启动时会创建这些表:
|
||||
|
||||
### 4.1 `records`
|
||||
|
||||
保存考勤记录。
|
||||
|
||||
| 字段 | 类型 | 含义 |
|
||||
| --- | --- | --- |
|
||||
| `id` | INTEGER PRIMARY KEY AUTOINCREMENT | 自增主键 |
|
||||
| `timestamp` | TEXT | 签到时间 |
|
||||
| `student_id` | TEXT | 学号 |
|
||||
| `name` | TEXT | 名称 |
|
||||
| `confidence` | TEXT | 置信度 |
|
||||
| `status` | TEXT | 状态,例如 `success` |
|
||||
| `class_id` | TEXT | 班级编号 |
|
||||
|
||||
索引:
|
||||
|
||||
```sql
|
||||
idx_records_student_time(student_id,timestamp)
|
||||
idx_records_timestamp(timestamp)
|
||||
```
|
||||
|
||||
### 4.2 `kv_store`
|
||||
|
||||
保存配置型数据。
|
||||
|
||||
| key | value 内容 |
|
||||
| --- | --- |
|
||||
| `time_slots` | 时间段 JSON |
|
||||
| `mapping_config` | 学生姓名和班级名称映射 |
|
||||
| `sync_request` | K210 同步请求标志 |
|
||||
| `sync_version` | 全局同步版本号 |
|
||||
|
||||
### 4.3 `face_mappings`
|
||||
|
||||
保存 K210 原始 face_id 到真实学号的映射。
|
||||
|
||||
| 字段 | 含义 |
|
||||
| --- | --- |
|
||||
| `face_id` | K210 本地人脸编号 |
|
||||
| `student_id` | 真实学号 |
|
||||
|
||||
### 4.4 `pending_delete`
|
||||
|
||||
保存等待 K210 删除的任务。
|
||||
|
||||
| 字段 | 含义 |
|
||||
| --- | --- |
|
||||
| `task_id` | 删除任务 ID |
|
||||
| `face_id` | K210 需要删除的人脸 ID |
|
||||
| `student_id` | 对应学生 ID |
|
||||
| `created_at` | 创建时间 |
|
||||
| `status` | 状态,默认 `pending` |
|
||||
| `ack_at` | 确认时间 |
|
||||
|
||||
### 4.5 `device_sync_state`
|
||||
|
||||
保存各客户端同步状态。
|
||||
|
||||
| 字段 | 含义 |
|
||||
| --- | --- |
|
||||
| `client` | 客户端名,例如 `qt`、`stm32`、`k210` |
|
||||
| `last_seen_version` | 客户端最近看到的服务端版本 |
|
||||
| `last_ack_version` | 客户端最近确认的版本 |
|
||||
| `last_seen_at` | 最近访问时间 |
|
||||
|
||||
## 5. 默认配置
|
||||
|
||||
| 配置 | 当前值 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `HTTP_PORT` | `8082` | HTTP 监听端口 |
|
||||
| `ATTENDANCE_BIND_HOST` | `0.0.0.0` | 默认监听地址,可用环境变量覆盖 |
|
||||
| `DEFAULT_API_TOKEN` | `atk_nKfVWLhMjL0RGSfRll3R_sdJS6IrIjuV` | 默认 API Token |
|
||||
| `DEFAULT_CORS_ORIGIN` | `http://localhost` | 默认 CORS 来源 |
|
||||
| `MAX_JSON_BODY_SIZE` | `64 KB` | 普通 JSON 请求体上限 |
|
||||
| `MAX_PHOTO_BODY_SIZE` | `512 KB` | 照片上传请求体上限 |
|
||||
| `DEFAULT_TIMESLOTS_JSON` | `{"time_slots":[]}` | 默认时间段为空 |
|
||||
|
||||
可以通过环境变量覆盖:
|
||||
|
||||
```powershell
|
||||
$env:ATTENDANCE_BIND_HOST="0.0.0.0"
|
||||
$env:ATTENDANCE_API_TOKEN="你的Token"
|
||||
$env:ATTENDANCE_CORS_ORIGIN="http://localhost"
|
||||
```
|
||||
|
||||
## 6. 鉴权规则
|
||||
|
||||
服务端对大多数接口要求请求头:
|
||||
|
||||
```text
|
||||
X-Api-Token: <Token>
|
||||
```
|
||||
|
||||
允许不带 Token 的情况:
|
||||
|
||||
1. `OPTIONS` 预检请求。
|
||||
2. `GET /api/health`。
|
||||
|
||||
新接口和旧接口都使用同样的鉴权逻辑。
|
||||
|
||||
## 7. 路由兼容关系
|
||||
|
||||
服务端内部仍有一些旧路径,例如 `/api/records`、`/api/timeslots`。为了让接口更清晰,代码提供了 `/api/v1/...` 新路径,并在服务端内部转换到旧路径。
|
||||
|
||||
| 新路径 | 内部兼容路径 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `/api/v1/system/health` | `/api/health` | 健康检查 |
|
||||
| `/api/v1/system/time` | `/api/time` | 获取服务器时间 |
|
||||
| `/api/v1/attendance/checkins` | `/api/checkin` | 加密签到上传 |
|
||||
| `/api/v1/attendance/records` | `/api/records` | 获取/删除考勤记录 |
|
||||
| `/api/v1/attendance/records/clear` | `/api/clear` | 清空记录 |
|
||||
| `/api/v1/attendance/statistics` | `/api/statistics` | 获取统计 |
|
||||
| `/api/v1/attendance/duplicates` | `/api/check_duplicate` | 查重 |
|
||||
| `/api/v1/attendance/today` | `/api/today_records` | 今日某时间段记录 |
|
||||
| `/api/v1/config/time-slots` | `/api/timeslots` | 时间段 |
|
||||
| `/api/v1/config/mappings` | `/api/mapping_config` | 学生/班级映射 |
|
||||
| `/api/v1/faces/mappings` | `/api/face_id_mapping` | 人脸映射 |
|
||||
| `/api/v1/faces/photos` | `/api/face_photos` | 照片列表 |
|
||||
| `/api/v1/faces/photos/<id>` | `/api/face_photo/<id>` 或 `/api/face_photo_simple/<id>` | 下载/上传照片 |
|
||||
| `/api/v1/faces/student-ids` | `/api/all_student_ids` | 全部学生 ID |
|
||||
| `/api/v1/faces/pending-delete` | `/api/pending_delete` | 待删除任务 |
|
||||
| `/api/v1/faces/delete-ack` | `/api/confirm_delete` | 旧式删除确认 |
|
||||
| `/api/v1/faces/<id>` | `/api/face/<id>` | 删除人脸 |
|
||||
| `/api/v1/sync/request` | `/api/sync_request` | 同步请求标志 |
|
||||
| `/api/v1/sync/request/ack` | `/api/sync_ack` | 同步请求确认 |
|
||||
| `/api/v1/sync/trigger` | `/api/trigger_sync` | 触发同步 |
|
||||
|
||||
文档推荐使用 `/api/v1/...`,旧路径主要为了兼容旧代码。
|
||||
|
||||
## 8. 核心 API
|
||||
|
||||
以下示例默认服务端地址是:
|
||||
|
||||
```text
|
||||
http://127.0.0.1:8082
|
||||
```
|
||||
|
||||
### 8.1 健康检查
|
||||
|
||||
```text
|
||||
GET /api/v1/system/health
|
||||
```
|
||||
|
||||
返回示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"time": "2026-05-01 10:00:00",
|
||||
"storage": "sqlite",
|
||||
"database": "attendance.db",
|
||||
"database_ok": true,
|
||||
"quick_check": "ok",
|
||||
"sync_version": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 存储状态
|
||||
|
||||
```text
|
||||
GET /api/v1/system/storage
|
||||
```
|
||||
|
||||
用于检查 SQLite、记录数量、照片数量、待删除任务数量等。
|
||||
|
||||
### 8.3 获取服务器时间
|
||||
|
||||
```text
|
||||
GET /api/v1/system/time
|
||||
```
|
||||
|
||||
返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"epoch": 1777600800,
|
||||
"server_time": "2026-05-01 10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
STM32 使用 `epoch` 转成 UTC+8 时间。
|
||||
|
||||
### 8.4 加密签到上传
|
||||
|
||||
```text
|
||||
POST /api/v1/attendance/checkins
|
||||
X-Encrypted: AES128-CBC
|
||||
X-Api-Token: <Token>
|
||||
```
|
||||
|
||||
请求体是 Base64 字符串。解密后的 JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"student_id": "20240001",
|
||||
"name": "张三",
|
||||
"confidence": "0.95",
|
||||
"status": "success",
|
||||
"class_id": "1"
|
||||
}
|
||||
```
|
||||
|
||||
字段校验:
|
||||
|
||||
| 字段 | 要求 |
|
||||
| --- | --- |
|
||||
| `student_id` | 必填,安全 ID,长度不超过 32 |
|
||||
| `name` | 可选,长度不超过 64 |
|
||||
| `confidence` | 必须是 0.0 到 1.0 |
|
||||
| `status` | 只能是 `success`、`failed`、`late` |
|
||||
| `class_id` | 可选,安全 ID,长度不超过 32,默认 `0` |
|
||||
|
||||
成功返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "签到成功",
|
||||
"timestamp": "2026-05-01 10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
### 8.5 获取考勤记录
|
||||
|
||||
```text
|
||||
GET /api/v1/attendance/records?limit=1000&offset=0
|
||||
```
|
||||
|
||||
`limit` 范围是 1 到 5000,`offset` 范围是 0 到 1000000。
|
||||
|
||||
返回数组:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"timestamp": "2026-05-01 08:10:00",
|
||||
"student_id": "20240001",
|
||||
"name": "张三",
|
||||
"confidence": 0.95,
|
||||
"status": "success",
|
||||
"class_id": "1"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
如果请求头带:
|
||||
|
||||
```text
|
||||
X-Encrypted-Response: true
|
||||
```
|
||||
|
||||
服务端会把响应 JSON 加密后以 Base64 返回。Qt 当前普通记录请求没有启用这个请求头。
|
||||
|
||||
### 8.6 获取统计
|
||||
|
||||
```text
|
||||
GET /api/v1/attendance/statistics
|
||||
```
|
||||
|
||||
返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"total": 120,
|
||||
"today": 8,
|
||||
"server_time": "2026-05-01 10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
### 8.7 清空记录
|
||||
|
||||
```text
|
||||
POST /api/v1/attendance/records/clear
|
||||
```
|
||||
|
||||
成功后会删除 `records` 表中的所有记录,并提升同步版本。
|
||||
|
||||
### 8.8 删除单条记录
|
||||
|
||||
```text
|
||||
DELETE /api/v1/attendance/records?timestamp=2026-05-01%2008%3A10%3A00&student_id=20240001
|
||||
```
|
||||
|
||||
成功后提升同步版本。
|
||||
|
||||
### 8.9 时间段配置
|
||||
|
||||
获取:
|
||||
|
||||
```text
|
||||
GET /api/v1/config/time-slots
|
||||
```
|
||||
|
||||
保存:
|
||||
|
||||
```text
|
||||
POST /api/v1/config/time-slots
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
请求体:
|
||||
|
||||
```json
|
||||
{
|
||||
"time_slots": [
|
||||
{
|
||||
"name": "上午签到",
|
||||
"start_time": "08:00",
|
||||
"end_time": "09:30",
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
当前默认值是:
|
||||
|
||||
```json
|
||||
{
|
||||
"time_slots": []
|
||||
}
|
||||
```
|
||||
|
||||
服务端还包含旧默认四时段的迁移判断:如果数据库里保存的是旧的四个默认时段,会自动改为空数组。
|
||||
|
||||
### 8.10 重复签到检查
|
||||
|
||||
```text
|
||||
GET /api/v1/attendance/duplicates?student_id=20240001&slot_start=08:00&slot_end=09:30
|
||||
```
|
||||
|
||||
用于 STM32 在线时补充查重。
|
||||
|
||||
### 8.11 今日某时段已签到记录
|
||||
|
||||
```text
|
||||
GET /api/v1/attendance/today?slot_start=08:00&slot_end=09:30
|
||||
```
|
||||
|
||||
返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"date": "2026-05-01",
|
||||
"records": ["20240001", "20240002"]
|
||||
}
|
||||
```
|
||||
|
||||
STM32 开机后用它构建本地今日缓存。
|
||||
|
||||
### 8.12 学生姓名和班级名称映射
|
||||
|
||||
```text
|
||||
GET /api/v1/config/mappings
|
||||
POST /api/v1/config/mappings
|
||||
```
|
||||
|
||||
格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"student_name_map": {
|
||||
"20240001": "张三"
|
||||
},
|
||||
"class_name_map": {
|
||||
"1": "软件工程一班"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这个映射主要给 Qt 显示使用,不改变 STM32 签到上传的原始学号。
|
||||
|
||||
### 8.13 人脸照片
|
||||
|
||||
照片列表:
|
||||
|
||||
```text
|
||||
GET /api/v1/faces/photos
|
||||
```
|
||||
|
||||
返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"photos": [
|
||||
{
|
||||
"id": "1",
|
||||
"filename": "1.jpg"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
上传照片:
|
||||
|
||||
```text
|
||||
POST /api/v1/faces/photos/1
|
||||
Content-Type: image/jpeg
|
||||
```
|
||||
|
||||
下载照片:
|
||||
|
||||
```text
|
||||
GET /api/v1/faces/photos/1
|
||||
```
|
||||
|
||||
成功时返回 `image/jpeg`。
|
||||
|
||||
### 8.14 人脸 ID 映射
|
||||
|
||||
```text
|
||||
GET /api/v1/faces/mappings
|
||||
POST /api/v1/faces/mappings
|
||||
```
|
||||
|
||||
格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"mappings": {
|
||||
"1": "20240001"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
保存映射后服务端会:
|
||||
|
||||
1. 写入 `face_mappings`。
|
||||
2. 尝试按映射重命名照片。
|
||||
3. 提升同步版本。
|
||||
4. 设置 K210 同步请求标志。
|
||||
|
||||
### 8.15 获取全部学生 ID
|
||||
|
||||
```text
|
||||
GET /api/v1/faces/student-ids
|
||||
```
|
||||
|
||||
从 `records` 表中提取所有出现过的学生 ID。
|
||||
|
||||
### 8.16 删除人脸
|
||||
|
||||
```text
|
||||
DELETE /api/v1/faces/20240001
|
||||
DELETE /api/v1/faces/20240001?delete_records=true
|
||||
```
|
||||
|
||||
服务端会:
|
||||
|
||||
1. 删除相关照片。
|
||||
2. 删除相关映射。
|
||||
3. 如果 `delete_records=true`,删除该学生相关考勤记录。
|
||||
4. 创建 K210 待删除任务。
|
||||
5. 提升同步版本。
|
||||
6. 设置同步请求标志。
|
||||
|
||||
返回示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"photo_deleted": true,
|
||||
"mapping_deleted": true,
|
||||
"records_deleted": 3,
|
||||
"k210_pending": true,
|
||||
"sync_requested": true
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 统一同步接口
|
||||
|
||||
### 9.1 获取版本
|
||||
|
||||
```text
|
||||
GET /api/v1/sync/version
|
||||
```
|
||||
|
||||
返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 6,
|
||||
"server_time": "2026-05-01 10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
### 9.2 获取同步状态
|
||||
|
||||
```text
|
||||
GET /api/v1/sync/state?client=<client>&last_version=<version>
|
||||
```
|
||||
|
||||
`client` 可取:
|
||||
|
||||
| client | 服务端返回内容 |
|
||||
| --- | --- |
|
||||
| `stm32` | `time_slots` |
|
||||
| `k210` | `face_mappings`、`pending_delete`、`delete_tasks` |
|
||||
| `qt` | 记录、统计、时间段、映射、照片列表、学生 ID、人脸映射 |
|
||||
| `all` 或空 | 尽可能返回全部 |
|
||||
|
||||
如果没有变化:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 6,
|
||||
"changed": false,
|
||||
"client": "stm32",
|
||||
"server_time": "2026-05-01 10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
如果有变化:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 7,
|
||||
"changed": true,
|
||||
"client": "k210",
|
||||
"server_time": "2026-05-01 10:00:00",
|
||||
"state": {
|
||||
"face_mappings": {},
|
||||
"pending_delete": [],
|
||||
"delete_tasks": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 9.3 同步确认
|
||||
|
||||
```text
|
||||
POST /api/v1/sync/ack
|
||||
```
|
||||
|
||||
请求体:
|
||||
|
||||
```json
|
||||
{
|
||||
"client": "k210",
|
||||
"version": 12,
|
||||
"deleted": ["2", "3"],
|
||||
"task_ids": ["2-1770000000", "3-1770000001"]
|
||||
"version": 7,
|
||||
"deleted": ["1"],
|
||||
"task_ids": ["task-1"]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 人脸删除与同步控制
|
||||
- `DELETE /api/v1/faces/<student_id>?delete_records=true`
|
||||
- `GET /api/v1/faces/pending-delete`
|
||||
- `POST /api/v1/faces/delete-ack`
|
||||
- `GET /api/v1/sync/request`
|
||||
- `POST /api/v1/sync/request/ack`
|
||||
- `POST /api/v1/sync/trigger`
|
||||
用途:
|
||||
|
||||
说明:这些是 v1 下的兼容控制接口;推荐设备端优先使用统一同步接口,只有手动调试或兼容旧流程时才单独调用。
|
||||
1. 记录客户端已经确认的版本。
|
||||
2. 移除已经完成的删除任务。
|
||||
3. 必要时再次提升同步版本。
|
||||
|
||||
### 4.6 旧接口兼容
|
||||
服务端内部仍保留旧 `/api/...` 路由兼容层,便于历史程序临时访问;新代码和新文档统一使用 `/api/v1/...`。
|
||||
## 10. 编译与运行
|
||||
|
||||
## 5. 编译与运行
|
||||
Windows(示例):
|
||||
```bash
|
||||
cd server
|
||||
### 10.1 Windows MinGW 示例
|
||||
|
||||
如果已经装好 MinGW、OpenSSL、SQLite:
|
||||
|
||||
```powershell
|
||||
g++ -o server_encrypted.exe server_encrypted.cpp -lws2_32 -lcrypto -lssl -lsqlite3 -std=c++11
|
||||
server_encrypted.exe
|
||||
.\server_encrypted.exe
|
||||
```
|
||||
|
||||
Linux(示例):
|
||||
### 10.2 Linux 示例
|
||||
|
||||
```bash
|
||||
cd server
|
||||
g++ -o server_encrypted server_encrypted.cpp -lcrypto -lssl -lsqlite3 -lpthread -std=c++11
|
||||
g++ -o server_encrypted server_encrypted.cpp -lcrypto -lssl -lsqlite3 -std=c++11 -pthread
|
||||
./server_encrypted
|
||||
```
|
||||
|
||||
说明:服务端启动时会自动创建 `attendance.db`。如果检测到旧 CSV/JSON 文件,会在首次启动时导入;之后以后端 API 和 SQLite 为准。
|
||||
### 10.3 运行目录建议
|
||||
|
||||
## 6. 备份与恢复
|
||||
服务端启动时如果发现已有 `attendance.db`,会先复制到 `backups/attendance_YYYY-MM-DD_HH-MM-SS.db`。备份失败时服务端会停止启动,避免在没有恢复点的情况下继续写入。
|
||||
|
||||
恢复步骤:
|
||||
1. 停止 `server_encrypted`。
|
||||
2. 将当前 `attendance.db` 改名保留,例如 `attendance.broken.db`。
|
||||
3. 从 `backups/` 选择最近可用备份,复制为 `attendance.db`。
|
||||
4. 重新启动服务端,访问 `/api/v1/system/storage`,确认 `ok:true`、`quick_check:"ok"`。
|
||||
|
||||
## 7. 公网部署安全
|
||||
本机或内网演示可以直接监听 `0.0.0.0:8082`。公网部署建议:
|
||||
- 设置 `ATTENDANCE_BIND_HOST=127.0.0.1`,只让服务端监听本机。
|
||||
- 使用 Nginx 或 Caddy 终止 HTTPS,并由反向代理转发到 `127.0.0.1:8082`。
|
||||
- 配置 HTTPS 后立即轮换 `ATTENDANCE_API_TOKEN`、设备端 Token 和相关密钥。
|
||||
- 反向代理层继续限制来源 IP、请求体大小和访问日志脱敏。
|
||||
|
||||
## 8. 自动化回归
|
||||
服务端启动后可运行:
|
||||
建议在 `server/` 目录下运行,这样数据库、照片目录和备份目录都会生成在 `server/` 下面:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\regression_api_tests.ps1 -BaseUrl "http://127.0.0.1:8082" -ApiToken "change-me-token"
|
||||
cd D:\University\graduation\code\Reconstruct_Qt\server
|
||||
.\server_encrypted.exe
|
||||
```
|
||||
|
||||
脚本覆盖 health、storage、time、sync、records、statistics、time-slots、mappings、faces 等低风险接口;真实 AES 签到正文和真实照片上传仍保留手动验证。
|
||||
## 11. 安全注意事项
|
||||
|
||||
## 9. 版本说明
|
||||
仓库仅保留当前推荐版本:`server_encrypted.cpp`。旧版实验服务端与测试脚本已清理,避免误部署非鉴权接口。
|
||||
1. 默认 Token 已写在代码里,不适合直接暴露公网。
|
||||
2. 当前是 HTTP 明文传输,公网部署建议放到 HTTPS 反向代理后面。
|
||||
3. AES Key/IV 是固定值,演示可以,生产环境不建议固定写死。
|
||||
4. SQLite 数据库和照片目录需要定期备份。
|
||||
5. `ATTENDANCE_CORS_ORIGIN` 不建议设置成任意来源。
|
||||
6. 服务器运行目录要限制写权限,避免误删数据。
|
||||
|
||||
## 10. 关键一致性要求
|
||||
- AES Key/IV 必须与 STM32、Qt 完全一致。
|
||||
- 若 Qt 无法解析记录,先检查是否误连到非加密版本服务端。
|
||||
|
||||
## 11. 后续优化
|
||||
服务端当前已经完成 SQLite 主存储、v1 接口、自动备份和统一同步模型。后续需要继续跟踪的风险和优化项已统一记录在 `docs/05_项目审查问题清单.md`。
|
||||
## 12. 常见问题
|
||||
|
||||
| 现象 | 可能原因 | 处理 |
|
||||
| --- | --- | --- |
|
||||
| 401 Unauthorized | 没带 `X-Api-Token` 或 Token 不一致 | 检查四端 Token |
|
||||
| Qt 连接失败 | 服务端没启动、地址错、防火墙拦截 | 访问 `/api/v1/system/health` |
|
||||
| STM32 解密失败 | AES Key/IV 不一致或请求体不是 Base64 密文 | 对照三端 AES 参数 |
|
||||
| 时间段总是旧数据 | SQLite 中已有旧配置 | 当前代码会清理旧默认四时段;自定义旧配置需手动保存为空 |
|
||||
| K210 删除不同步 | K210 未拉取同步状态或 ACK 失败 | 看 `/api/v1/sync/state?client=k210&last_version=0` |
|
||||
| 照片上传失败 | 图片超过 512KB、face_id 非法、目录不可写 | 检查服务端日志和 `faces/` 权限 |
|
||||
|
||||
Reference in New Issue
Block a user