mirror of
https://github.com/ZeroCatDev/ClassworksKV.git
synced 2025-10-22 02:03:11 +00:00
11 KiB
11 KiB
前端迁移指南
概述
本文档描述了后端中间件系统的重构,以及前端需要如何适配这些变化。核心变化是统一了设备信息获取和权限验证流程。
核心变化
1. 统一的设备中间件系统
后端现在使用统一的中间件处理所有与设备UUID相关的操作:
deviceMiddleware
: 自动获取或创建设备,设备不存在时自动创建requireWriteAuth
: 验证写权限,检查设备密码tokenAuth
: Token认证,用于应用访问
2. 设备自动创建
重要变化: 当使用一个新的UUID访问API时,后端会自动创建该设备,无需手动调用创建设备接口。
3. 权限模型
- 读操作: 永远不需要密码
- 写操作: 如果设备设置了密码则需要验证,否则直接允许
场景1: 基于UUID的直接访问
适用于:用户直接操作设备数据(设备配置、设备管理等)
读操作(无需密码)
请求方式: GET /device/:deviceUuid/*
特点:
- 设备不存在时自动创建
- 无需提供密码
- 任何知道UUID的人都可以读取
请求示例:
GET /device/550e8400-e29b-41d4-a716-446655440000/info
Headers:
x-site-key: your-site-key
成功响应 (200):
{
"id": 1,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": null,
"password": null,
"passwordHint": null,
"accountId": null,
"createdAt": "2025-01-30T10:00:00.000Z",
"updatedAt": "2025-01-30T10:00:00.000Z"
}
写操作(需要密码验证)
请求方式: POST|PUT|DELETE /device/:deviceUuid/*
特点:
- 设备不存在时自动创建
- 如果设备设置了密码,必须提供正确密码
- 如果设备没有密码,直接允许写入
密码提供方式
方式1: 通过请求体(推荐)
POST /device/550e8400-e29b-41d4-a716-446655440000/config
Headers:
Content-Type: application/json
x-site-key: your-site-key
Body:
{
"password": "device-password",
"data": {
"theme": "dark",
"language": "zh-CN"
}
}
方式2: 通过查询参数
POST /device/550e8400-e29b-41d4-a716-446655440000/config?password=device-password
Headers:
Content-Type: application/json
x-site-key: your-site-key
Body:
{
"data": {
"theme": "dark",
"language": "zh-CN"
}
}
成功响应 (200):
{
"message": "数据已更新",
"updatedAt": "2025-01-30T10:05:00.000Z"
}
错误响应 - 需要密码 (401):
{
"statusCode": 401,
"message": "此操作需要密码",
"passwordHint": "您的生日(8位数字)"
}
错误响应 - 密码错误 (401):
{
"statusCode": 401,
"message": "密码错误"
}
场景2: 基于Token的应用访问
适用于:应用访问KV存储数据
步骤1: 获取Token
请求方式: POST /apps/:appId/authorize
请求示例:
POST /apps/1/authorize
Headers:
Content-Type: application/json
x-site-key: your-site-key
Body:
{
"deviceUuid": "550e8400-e29b-41d4-a716-446655440000",
"password": "device-password",
"note": "我的应用授权"
}
说明:
deviceUuid
: 必填,设备UUIDpassword
: 如果设备有密码则必填note
: 可选,授权备注
成功响应 (200):
{
"token": "clxxx123456789abcdefg",
"appId": 1,
"appName": "我的应用",
"deviceUuid": "550e8400-e29b-41d4-a716-446655440000",
"deviceName": null,
"note": "我的应用授权",
"authorizedAt": "2025-01-30T10:00:00.000Z"
}
错误响应 - 需要密码 (401):
{
"statusCode": 401,
"message": "此操作需要密码",
"passwordHint": "您的生日(8位数字)"
}
步骤2: 使用Token访问KV存储
Token提供方式
方式1: Authorization Header(推荐)
Headers:
Authorization: Bearer clxxx123456789abcdefg
方式2: Query参数
?token=clxxx123456789abcdefg
方式3: Request Body
{
"token": "clxxx123456789abcdefg",
...
}
KV API端点
方法 | 端点 | 说明 |
---|---|---|
GET | /kv |
列出所有键(含元数据) |
GET | /kv/_keys |
列出所有键名(仅键名) |
GET | /kv/:key |
获取键值 |
GET | /kv/:key/metadata |
获取键元数据 |
POST | /kv/:key |
创建/更新键值 |
POST | /kv/_batchimport |
批量导入 |
DELETE | /kv/:key |
删除键值 |
GET /kv - 列出所有键(含元数据)
请求示例:
GET /kv?sortBy=key&sortDir=asc&limit=10&skip=0
Headers:
Authorization: Bearer clxxx123456789abcdefg
x-site-key: your-site-key
查询参数:
sortBy
: 排序字段(key/createdAt/updatedAt),默认 keysortDir
: 排序方向(asc/desc),默认 asclimit
: 每页数量,默认 100skip
: 跳过数量,默认 0
成功响应 (200):
{
"items": [
{
"deviceId": 1,
"key": "config",
"metadata": {
"creatorIp": "192.168.1.1",
"createdAt": "2025-01-30T10:00:00.000Z",
"updatedAt": "2025-01-30T10:00:00.000Z"
}
},
{
"deviceId": 1,
"key": "user.name",
"metadata": {
"creatorIp": "192.168.1.1",
"createdAt": "2025-01-30T10:01:00.000Z",
"updatedAt": "2025-01-30T10:01:00.000Z"
}
}
],
"total_rows": 25,
"load_more": "/kv?sortBy=key&sortDir=asc&limit=10&skip=10"
}
GET /kv/_keys - 列出所有键名
请求示例:
GET /kv/_keys?limit=50&skip=0
Headers:
Authorization: Bearer clxxx123456789abcdefg
x-site-key: your-site-key
成功响应 (200):
{
"keys": ["config", "user.name", "user.theme", "app.settings"],
"total_rows": 4,
"current_page": {
"limit": 50,
"skip": 0,
"count": 4
}
}
GET /kv/:key - 获取键值
请求示例:
GET /kv/config
Headers:
Authorization: Bearer clxxx123456789abcdefg
x-site-key: your-site-key
成功响应 (200):
{
"theme": "dark",
"language": "zh-CN",
"fontSize": 14
}
错误响应 - 键不存在 (404):
{
"statusCode": 404,
"message": "未找到键名为 'config' 的记录"
}
GET /kv/:key/metadata - 获取键元数据
请求示例:
GET /kv/config/metadata
Headers:
Authorization: Bearer clxxx123456789abcdefg
x-site-key: your-site-key
成功响应 (200):
{
"deviceId": 1,
"key": "config",
"metadata": {
"creatorIp": "192.168.1.1",
"createdAt": "2025-01-30T10:00:00.000Z",
"updatedAt": "2025-01-30T10:05:00.000Z"
}
}
POST /kv/:key - 创建/更新键值
请求示例:
POST /kv/config
Headers:
Authorization: Bearer clxxx123456789abcdefg
Content-Type: application/json
x-site-key: your-site-key
Body:
{
"theme": "dark",
"language": "zh-CN",
"fontSize": 14
}
成功响应 (200):
{
"deviceId": 1,
"key": "config",
"created": false,
"updatedAt": "2025-01-30T10:10:00.000Z"
}
说明:
created
: true表示新建,false表示更新
错误响应 - 空值 (400):
{
"statusCode": 400,
"message": "请提供有效的JSON值"
}
POST /kv/_batchimport - 批量导入
请求示例:
POST /kv/_batchimport
Headers:
Authorization: Bearer clxxx123456789abcdefg
Content-Type: application/json
x-site-key: your-site-key
Body:
{
"config": {
"theme": "dark",
"language": "zh-CN"
},
"user.name": {
"firstName": "John",
"lastName": "Doe"
},
"app.settings": {
"notifications": true
}
}
成功响应 (200):
{
"deviceId": 1,
"total": 3,
"successful": 3,
"failed": 0,
"results": [
{
"key": "config",
"created": false
},
{
"key": "user.name",
"created": true
},
{
"key": "app.settings",
"created": true
}
]
}
部分失败响应 (200):
{
"deviceId": 1,
"total": 3,
"successful": 2,
"failed": 1,
"results": [
{
"key": "config",
"created": false
},
{
"key": "user.name",
"created": true
}
],
"errors": [
{
"key": "app.settings",
"error": "Invalid value"
}
]
}
DELETE /kv/:key - 删除键值
请求示例:
DELETE /kv/config
Headers:
Authorization: Bearer clxxx123456789abcdefg
x-site-key: your-site-key
成功响应 (204):
无响应体
错误响应 - 键不存在 (404):
{
"statusCode": 404,
"message": "未找到键名为 'config' 的记录"
}
错误码参考
状态码 | 说明 | 场景 |
---|---|---|
200 | 成功 | 操作成功 |
204 | 成功(无内容) | 删除成功 |
400 | 请求错误 | 参数缺失或格式错误 |
401 | 未授权 | 需要密码、密码错误、Token无效 |
403 | 禁止访问 | 权限不足 |
404 | 未找到 | 资源不存在 |
500 | 服务器错误 | 服务器内部错误 |
401错误详解
需要密码
{
"statusCode": 401,
"message": "此操作需要密码",
"passwordHint": "您的生日(8位数字)"
}
处理方式: 提示用户输入密码,使用 passwordHint
作为提示信息
密码错误
{
"statusCode": 401,
"message": "密码错误"
}
处理方式: 提示用户密码错误,允许重试
Token无效
{
"statusCode": 401,
"message": "未提供身份验证令牌"
}
或
{
"statusCode": 401,
"message": "无效的身份验证令牌"
}
处理方式: 清除本地Token,引导用户重新授权
迁移检查清单
Phase 1: 基础适配
- 移除手动创建设备的逻辑(设备会自动创建)
- 更新密码提供方式(从header改为body/query)
- 实现统一的错误处理
- 更新API端点路径
Phase 2: Token集成
- 实现应用授权流程(POST /apps/:appId/authorize)
- 集成Token到KV操作
- 实现Token存储和管理(localStorage)
- 处理Token过期/无效场景
Phase 3: 优化
- 封装统一的API客户端
- 实现请求重试机制
- 添加Loading状态管理
- 优化错误提示用户体验
Phase 4: 测试
- 测试设备自动创建
- 测试密码验证流程(需要密码、密码错误、密码正确)
- 测试Token授权流程
- 测试各种错误场景(404、401、400等)
关键注意事项
1. 设备自动创建
- ✅ 无需手动创建设备,首次访问自动创建
- ✅ 简化前端流程,减少API调用
- ⚠️ 确保UUID使用正确的格式(建议使用uuidv4)
2. 密码处理
- ✅ 读操作永远不需要密码
- ✅ 写操作只在设备设置了密码时才需要
- ⚠️ 密码通过body或query提供,不要放在header中
- ⚠️ 注意区分"需要密码"和"密码错误"两种情况
3. Token管理
- ✅ Token一次获取,可重复使用
- ✅ Token与设备和应用绑定
- ⚠️ Token需要安全存储(localStorage/sessionStorage)
- ⚠️ Token失效时需要重新授权
4. Header要求
- 所有请求必须携带
x-site-key
header - Token认证使用
Authorization: Bearer <token>
header(推荐)