晴发文选择书籍和难度后,点击发文即可
服务器地址:http://your-server:8000
客户端首先需要获取服务器的RSA公钥用于加密:
GET /api/race/public_key
返回:
{
"public_key": "-----BEGIN RSA PUBLIC KEY-----\\n...\\n-----END RSA PUBLIC KEY-----"
}
获取所有启用的赛文(返回数据已加密):
GET /api/race/list
返回(加密):
{
"encrypted_data": "base64加密字符串"
}
解密后:
{
"success": true,
"races": [
{
"id": 1,
"name": "每日赛文",
"difficulty_group": 3,
"allow_resubmit": false
}
]
}
GET /api/race/init?raceId={raceId}
Authorization: Bearer {token}
参数:
- raceId: 赛文ID(必填)
返回:
{
"version": "1",
"algorithm": "RSA-OAEP-256+A256GCM",
"issuedAt": 1710000000000,
"contentType": "application/json",
"encryptedKey": "Base64(RSA-OAEP(AESKey))",
"iv": "Base64(GCM IV)",
"encryptedData": "Base64(AES-GCM(JSON payload))"
}
解密后的 payload:
{
"raceId": 1,
"articleId": 12,
"content": "今日赛文正文",
"sessionNonce": "一次性challenge",
"issuedAt": 1710000000000,
"expireAt": 1710000600000,
"serverPublicKey": "Base64服务器公钥",
"keyId": "当前服务器密钥标识"
}
说明:
- /api/race/init 的 HTTP 响应不再直接暴露 content
- 客户端先调用 init 获取加密 envelope,再使用本地赛文私钥解密出文章、challenge 和服务器公钥
- sessionNonce 仅可使用一次,过期或用过后需要重新初始化
POST /api/race/submit
Authorization: Bearer {token}
请求体:
{
"raceId": 1,
"userId": 1,
"encryptedData": "Base64(RSA-OAEP(payload))",
"signature": "Base64(客户端RSA签名)",
"clientTs": 1710000000000,
"keyId": "当前服务器密钥标识"
}
其中 payload 明文为:
{
"raceId": 1,
"articleId": 12,
"speed": 120.5,
"accuracy": 98.6,
"sessionNonce": "init 返回的一次性 challenge",
"clientTs": 1710000000000
}
说明:
- userId 为兼容字段,可不传;如果传了必须与当前登录用户一致
- 服务端会解密 encryptedData、校验 sessionNonce/clientTs/articleId/raceId,并使用注册时保存的客户端公钥验签
- challenge 只允许成功消费一次
GET /api/race/articles?race_id={race_id}&page={page}&page_size={page_size}
参数:
- race_id: 赛文ID(必填)
- page: 页码,从1开始(可选,默认1)
- page_size: 每页数量(可选,默认30,最大100)
返回:
{
"success": true,
"msg": "获取成功",
"articles": [
{
"id": 1,
"date": "2024-01-01",
"difficulty": 2.8,
"difficulty_level": "难",
"book_name": "红楼梦",
"char_count": 500,
"created_at": "2024-01-01 00:00:00"
}
],
"total": 100, // 总文章数
"page": 1, // 当前页
"page_size": 30,
"total_pages": 4 // 总页数
}
⚠️ 注意:此接口仅限本机或内网访问
GET /api/race/leaderboard?race_id={race_id}&date_str={date}&limit={limit}
参数:
- race_id: 赛文ID(必填)
- date_str: 日期(可选,格式YYYY-MM-DD,不传则为今天)
- limit: 返回记录数(可选,默认100)
返回(加密):
{
"encrypted_data": "base64加密字符串"
}
解密后:
{
"success": true,
"msg": "获取成功",
"date": "2024-01-01",
"leaderboard": [
{
"username": "用户名",
"speed": 120.5,
"time_cost": 248500,
"char_count": 500,
"keystroke": 150.0,
"code_length": 2.5,
"backspace_count": 10,
"key_count": 1250,
"key_accuracy": 95.5,
"word_rate": 60.0,
"input_method": "搜狗拼音",
"submit_time": "2024-01-01 12:00:00"
}
]
}
说明:
- 排行榜按速度(speed)降序排列
- 如果速度相同,则按键准(key_accuracy)降序排列
- 每个用户只显示当天的最佳成绩
GET /api/race/history?userId={optionalCurrentUserId}
Authorization: Bearer {token}
参数:
- userId: 可选;不传时默认当前登录用户,传了也必须与当前登录用户一致
返回:
- 当前登录用户最近 100 条赛文成绩记录
/api/race/init 获取加密 envelope,并在本地解密出正文与一次性 challenge完整文档请查看项目中的 赛文API文档.md
在这里管理书籍数据库、配置难度分级和处理书籍。
|,替换规则用 =>