# SoundGame Web 服务器(web/server/server.js) Node 零依赖(仅用内置模块)的静态文件 + 用户系统 API 服务器。 ## 启动 ```bash # 推荐:用项目自带 node tools/node/bin/node web/server/server.js # 或用封装脚本(打印局域网地址) bash web/serve.sh # 自定义端口(默认 8000) PORT=8001 tools/node/bin/node web/server/server.js ``` - 静态根目录:`web/`(`/` 即游戏大厅 `index.html`) - 数据目录:`web/server/data/`(首次启动自动创建) ## ⚠ 安全说明 这是**家庭局域网玩具级认证**,请勿暴露到公网: - PIN 以**明文**存储在 `data/users.json`; - token 永不过期,明文存于 `data/sessions.json`; - HTTP 明文传输,无 TLS、无防爆破、无速率限制。 用途仅限于同一 WiFi 下的家庭成员各自存档。公网 `game.xiangsilian.com` **不跑本服务**, 只托管静态文件(见 `docs/deploy.md`)。要公网开用户系统请换正经认证方案。 ## API 所有 API 请求/响应均为 JSON(`Content-Type: application/json`)。 错误响应统一为 `{ "error": "描述" }` + 相应 HTTP 状态码。 ### POST /api/register 注册新用户。 - 请求:`{ "username": "ming", "pin": "1234" }` - `username`:1~24 位字母/数字/中文/`_`/`-` - `pin`:4~6 位数字 - 成功:`201 { "ok": true, "username": "ming" }` - 失败:`400`(格式非法)/ `409 { "error": "用户名已被注册" }` ### POST /api/login 登录,返回 token。 - 请求:`{ "username": "ming", "pin": "1234" }` - 成功:`200 { "ok": true, "token": "<48 位随机 hex>", "username": "ming" }` - 失败:`401 { "error": "用户名或 PIN 错误" }` token 存内存并落盘 `data/sessions.json`(服务器重启后会话仍有效)。 ### GET /api/progress?game=xxx 读取某游戏的进度数据。 - 请求头:`Authorization: Bearer ` - 成功:`200 { "game": "escape", "data": { ... } }`(无存档时 `data` 为 `null`) - 失败:`401`(token 缺失/无效)/ `400`(缺少 game 参数) ### PUT /api/progress 写入某游戏的进度数据(覆盖该 game 键)。 - 请求头:`Authorization: Bearer ` - 请求:`{ "game": "escape", "data": { "summary": "已逃脱 2 次 / 最快 3:25", ... } }` - `game`:1~32 位字母/数字/`_`/`-`;大厅约定用 `_settings` 存用户设置 - `data`:任意 JSON 值;大厅卡片会展示 `data.summary` 字符串(若存在) - 成功:`200 { "ok": true, "game": "escape" }` - 失败:`401` / `400` ## 数据格式 ``` web/server/data/ ├── users.json { "": "" } ├── sessions.json { "": "" } └── .json { "": , ... } 一用户一文件 ``` 所有写入按文件串行排队(Promise 链),tmp + rename 原子落盘,并发请求不会写坏文件。 ## 静态服务 - MIME:`.ogg audio/ogg`、`.m4a audio/mp4`、`.js text/javascript`、 `.html text/html`、`.png image/png`、`.json application/json` 等; - 目录自动解析 `index.html`; - 支持简化版 HTTP Range(单段 `bytes=start-end` / `start-` / `-suffix`), 返回 206 + `Content-Range`,供音频元素拖动进度; - 路径穿越防护:请求路径限制在 `web/` 内。