57 lines
6.6 KiB
Markdown
57 lines
6.6 KiB
Markdown
|
|
# 官网赛事成绩接入
|
|||
|
|
|
|||
|
|
官网入口为 `/#/sports/competition` 的第 4 项「赛事成绩」,独立页面为 `/#/sports/results`。`YD_Event.Web` 的「官网赛事信息」页面负责维护与发布。原需求文档的系统 B(现场评分控制台)不在此接入链路中。
|
|||
|
|
|
|||
|
|
## 运行接口
|
|||
|
|
|
|||
|
|
接口使用 Node.js 18+,没有额外依赖。生产环境必须设置以下环境变量后运行 `npm run serve:competition-api`:
|
|||
|
|
|
|||
|
|
| 变量 | 用途 |
|
|||
|
|
|---|---|
|
|||
|
|
| `COMPETITION_DATA_PATH` | 持久化 JSON 文件路径;默认 `server/data/competition-state.json`。生产环境应放在持久化磁盘并备份 |
|
|||
|
|
| `COMPETITION_PORT` | 监听端口,默认 `8787` |
|
|||
|
|
| `COMPETITION_HOST` | 监听地址,默认 `127.0.0.1`;分机部署时设为赛事服务的私网 IP,并用防火墙限制 `8787` 端口只允许后台服务器访问 |
|
|||
|
|
| `COMPETITION_ADMIN_ALLOWED_IPS` | 允许直接访问内部管理接口的客户端 IP,逗号分隔;分机部署时填写 `YD_Event.Admin` 服务器的私网 IP。服务默认还允许本机环回地址 |
|
|||
|
|
| `COMPETITION_ALLOWED_ORIGINS` | 仅在浏览器直接访问赛事服务时需要;当前正式链路由 YD_Event.Admin 转发,官网浏览器不直接连接赛事服务 |
|
|||
|
|
|
|||
|
|
官网通过 `https://jitsi-web.yuedongsports.com/api/competition/state` 读取已发布数据。这个匿名只读接口由 YD_Event.Admin 提供,并通过私网读取赛事服务的 `/api/competition/state`;未发布时赛事服务只返回空态。管理页仍通过需要登录的 `/api/website-competition` 读取草稿及保存,不需要管理密钥。官网每 10 秒重新读取一次公开数据。
|
|||
|
|
|
|||
|
|
启动赛事服务时设置 `COMPETITION_HOST=<赛事服务私网 IP>` 和 `COMPETITION_ADMIN_ALLOWED_IPS=<后台服务器私网 IP>`;在 YD_Event.Admin 设置 `CompetitionApi__AdminUrl=http://<赛事服务私网 IP>:8787/api/competition/admin`。防火墙只允许后台服务器访问赛事服务的 `8787` 端口。先从后台服务器执行 `curl -i http://<赛事服务私网 IP>:8787/api/competition/ping`,确认服务返回 `200`。`jitsi-web.yuedongsports.com` 沿用现有 `/api/` 到 YD_Event.Admin 的代理,无需将公开请求直接代理到赛事服务。
|
|||
|
|
|
|||
|
|
若运维已应用旧版赛事 Nginx 片段,应改用 [`deploy/nginx/jitsi-competition-api.conf`](deploy/nginx/jitsi-competition-api.conf):只屏蔽公网 `/api/competition/admin`,让公开 `/api/competition/state` 走现有后台代理。修改后执行 `nginx -t` 再重载 Nginx。
|
|||
|
|
|
|||
|
|
部署后从官网域名验证公开接口及 CORS 响应头:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
curl -i -H 'Origin: https://www.yuedongsports.com' https://jitsi-web.yuedongsports.com/api/competition/state
|
|||
|
|
curl -i https://jitsi-web.yuedongsports.com/api/competition/admin
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
第一条请求应返回 `200` 和允许 `https://www.yuedongsports.com` 的 `Access-Control-Allow-Origin`;第二条公网管理路径应返回 `404`。若公开接口仍返回 `404`,先确认 YD_Event.Admin 已部署匿名只读控制器,且旧版 Nginx 赛事代理已移除。若返回 `502`,检查内网赛事服务、`CompetitionApi__AdminUrl` 和防火墙。内部管理接口只接受 `COMPETITION_ADMIN_ALLOWED_IPS` 中的来源地址;公网不可直连赛事服务的 `8787` 端口。
|
|||
|
|
|
|||
|
|
2026-10-20 排查发现:此前线上 `/api/competition/state` 返回后台生成的 `502`,原因是 `test_eventapi` 容器未配置 `CompetitionApi__AdminUrl`,同机没有监听 `8787` 的赛事数据服务。部署共享网络的赛事容器后,公开接口已恢复 `200`。当前后台响应由 Furion 包装为 `statusCode/data`,官网读取代码会解包其中的赛事 JSON;官网更新构建后才会使用这项解析修复。
|
|||
|
|
|
|||
|
|
若赛事服务与 `test_eventapi` 部署在同一台 Docker 主机,可按 [`deploy/competition-api/README.md`](deploy/competition-api/README.md) 启动独立的 Node 容器并共享后台容器的网络命名空间。两个容器因此共用回环地址,后台现有默认 `127.0.0.1:8787` 可用,且 `8787` 不需要对公网开放。后台容器被 Jenkins 重建时必须同步重建该赛事服务容器。
|
|||
|
|
|
|||
|
|
| 方法 | 路径 | 用途 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| GET | `jitsi-web.yuedongsports.com/api/competition/state` | YD_Event.Admin 的匿名只读接口;只返回已发布数据 |
|
|||
|
|
| GET/PUT | `jitsi-web.yuedongsports.com/api/website-competition` | 后台登录后读取草稿、保存或发布 |
|
|||
|
|
| GET/PUT | `<赛事服务私网 IP>:8787/api/competition/admin` | 仅供 YD_Event.Admin 内部调用;按来源 IP 放行 |
|
|||
|
|
|
|||
|
|
官网生产构建默认从 `https://jitsi-web.yuedongsports.com/api/competition/state` 读取,每 10 秒刷新一次,不再请求 `https://www.yuedongsports.com/api/competition/state`。如需覆盖,在构建官网时设置 `VITE_COMPETITION_API_URL` 为完整接口基地址。开发时官网 Vite 会把 `/api/competition` 代理到 `http://localhost:8787`,可用 `COMPETITION_API_TARGET` 覆盖。
|
|||
|
|
|
|||
|
|
YD_Event.Web 的「官网赛事信息」路由隐藏于菜单,未登录访问会跳转登录页;管理接口要求已有后台登录态。正式环境访问基地址为 `https://jitsi-web.yuedongsports.com/`。分机部署时将 `CompetitionApi__AdminUrl` 设为 `http://<赛事服务私网 IP>:8787/api/competition/admin`。后台管理和公开只读接口均由 YD_Event.Admin 通过私网转发到赛事服务。
|
|||
|
|
|
|||
|
|
升级两端服务后,旧的 `COMPETITION_ADMIN_TOKEN`、`CompetitionApi__AdminToken` 和 `CompetitionApi__AdminTokenFile` 可从部署配置中移除;它们不再被本功能读取。上线前由运维确认后台私网 IP 白名单、防火墙入站规则及公网管理路径屏蔽均已生效,再验证无密钥的后台保存流程。
|
|||
|
|
|
|||
|
|
## 上传格式
|
|||
|
|
|
|||
|
|
管理页提供包含填写说明和示例行的 Excel 模板。一次上传 `.xlsx` 文件会将赛程、全能成绩、挑战成绩、Battle、选手和纪录载入草稿,点击「保存官网赛事信息」才写入接口。页面也可下载当前数据的 Excel 文件。
|
|||
|
|
|
|||
|
|
Excel 工作表依次为「填写说明」「赛程」「全能成绩」「挑战成绩」「Battle场次」「选手」「纪录」。六张数据表的表头必须保留;删除示例行后可填写正式数据。全能成绩的名次使用官方成绩册数据,前台不重算名次。挑战成绩的「榜单」区分决赛和资格赛。
|
|||
|
|
|
|||
|
|
缺失的图片回退到默认头像。照片字段应使用浏览器可访问的 HTTPS 地址或官网同源路径;上传图片文件本身由现有图片存储服务负责。仓库内的 `public/competition-state.json` 是静态只读空态,不会存放管理后台的未发布数据。
|
|||
|
|
|
|||
|
|
运行接口验证:`node server/competition-api.smoke.mjs`。
|