1.重构websocket连接
This commit is contained in:
@@ -764,22 +764,35 @@
|
||||
- **移动端配置缺口**:**`POST /api/game/lobbyInit` 当前不下发 WebSocket 地址**;H5 需与运维约定同一套 `H5_WEBSOCKET_URL`(打包进前端配置、远程配置中心等),与 HTTP API 基址可不同域。
|
||||
- **混合内容**:若 H5 页面为 **HTTPS**,浏览器要求 WebSocket 使用 **`wss://`**,否则会被拦截。
|
||||
- **事件投递依赖 Redis**:HTTP 侧业务通过 **`GameWebSocketEventBus`**(Redis 列表)将事件投递到 WebSocket 进程;Redis 不可用或队列异常时,**除 `admin.live.snapshot` 外**的广播类推送可能收不到。后台若订阅了 `admin.live.snapshot`,服务端有**每秒直连构建快照**的兜底,不依赖队列。
|
||||
- **鉴权(重要)**:**当前 `GameWebSocketServer` 在握手阶段不校验** URL Query 中的 `token` / `auth_token` / `user-token` 等;**任何人拿到地址即可建立连接**(与 §1 HTTP 接口必须 `auth-token` + `user-token` 不同)。Query 中上述参数为**预留/习惯写法**,便于后续若要在 `onWebSocketConnect` 中实现鉴权再与 HTTP 对齐;**文档中若写「未登录返回 1101」属规划口径,非现网行为**。
|
||||
- **握手鉴权(2026-05 重构后强制)**:`GameWebSocketServer::onWebSocketConnect` 通过 `GameWebSocketAuthHelper::authorize` 校验 URL Query。两种合法身份:
|
||||
- **mobile(H5/移动端)**:必须同时携带 `auth_token`(同 HTTP `auth-token`)+ `user_token`(同 HTTP `user-token`,亦支持 `token` 同义)。校验通过后连接被绑定 `user_id`,分发器仅向其推送本人的 user 级主题。
|
||||
- **admin(后台/运维)**:必须携带 `admin_ws_token`(由后台 `wsConfig` 接口签发,写入 Redis Key `dfw:v1:ws:admin_token:{token}`,默认 TTL 7200s)。后台已 `wsConfig` 中把该 token 拼到 `ws_url` 一并返回,前端透传即可;admin 模式 `user_id=0`,可订阅任意主题并收到**全量** user 级推送(运维联调用)。
|
||||
- 任一身份不通过 → 服务端发送 `{"event":"ws.error","code":1101,"message":"Authentication failed: ..."}` 并立即 `close`。
|
||||
- **服务端按 user_id 过滤(user 级主题)**:以下 topic 的 `data.user_id` 必须 **等于** 当前连接绑定的 `user_id` 才会下发——**`bet.win` / `user.streak` / `wallet.changed` / `bet.accepted` / `auto.spin.progress`**。其它 topic(`period.tick` / `period.opened` / `jackpot.hit` / `admin.*` 等)按订阅广播。admin 模式不参与此过滤。
|
||||
- **心跳超时(服务端主动)**:连接 60s 内无任何上行报文(含 `ping`/`subscribe`)即被 server 主动 `close`,触发客户端走重连流程;避免半关闭的僵尸连接长期持有订阅却不能实际送达推送。
|
||||
- **独立日志通道 `ws`**:`runtime/logs/ws.log`(保留 7 天)。记录维度包含 `publish 入队 / popBatch 异常 / dispatch(topic/candidates/matched/skipped_not_owner/skipped_closed/send_failed)/ handshake_ok | denied / subscribe / pong / close idle / send failed` 等。排查"为什么没收到推送"时优先看此文件。
|
||||
- **订阅才有业务推送**:建连后仅会收到握手首帧(见下)及本连接已订阅主题的消息;不发送 `subscribe` 则收不到 `period.tick` 等(`admin.live.snapshot` 同上,需显式订阅)。
|
||||
|
||||
### 7.1 WebSocket 连接与消息
|
||||
|
||||
- **连接地址**:见 **§7.0**(环境变量 `H5_WEBSOCKET_URL` 或后台 `wsConfig` 返回的 `ws_url`)
|
||||
- **客户端**:浏览器原生 `WebSocket`(`ws://` / `wss://`)
|
||||
- **连接时携带参数(可选 / 预留)**:
|
||||
- URL Query 可带 `token`(与 HTTP 头 `user-token` 同义习惯)、`auth_token`(与 HTTP 头 `auth-token` 同义习惯)、`device_id`、`lang` 等,**当前服务端不解析、不校验**;若后续版本实现握手鉴权,以发布说明为准。
|
||||
- 示例(习惯写法):`wss://ws.example.com/ws?token=xxx&auth_token=xxx&device_id=ios_001&lang=zh`
|
||||
- **连接时必带 Query 参数(2026-05 起强制)**:
|
||||
- **H5/移动端**:`auth_token=<HTTP auth-token>` + `user_token=<HTTP user-token>`(亦支持 `token` 同义)。`device_id`、`lang` 仍可携带,但服务端不强制。
|
||||
- **后台**:`admin_ws_token=<wsConfig 返回的 admin_ws_token>`(后台 `wsConfig` 已直接把它拼到 `ws_url`,前端透传即可)。
|
||||
- 示例:
|
||||
- H5:`wss://ws.example.com/ws/?auth_token=xxx&user_token=yyy&device_id=ios_001&lang=zh`
|
||||
- 后台:`wss://ws.example.com/ws/?admin_ws_token=zzz`
|
||||
- 缺失任一必填字段或 token 失效 → 服务端回 `{"event":"ws.error","code":1101,...}` 后立即关闭连接。
|
||||
- **连接成功首帧(当前实现)**:
|
||||
- `event`:`ws.connected`
|
||||
- `message`:固定文案 `WebSocket connected`(便于联调日志)
|
||||
- `connection_id`:连接唯一标识(进程内)
|
||||
- `mode`:`mobile` | `admin`(2026-05 新增;表明本连接的鉴权身份)
|
||||
- `user_id`:int(2026-05 新增;mobile 模式为真实玩家 id,admin 模式为 0)
|
||||
- `server_time`:服务器时间戳(**秒**,int)
|
||||
- `heartbeat_interval`:建议心跳间隔(**秒**,当前实现固定为 `30`)
|
||||
- `idle_timeout`:服务端主动关闭的空闲秒数(**秒**,当前实现固定为 `60`;客户端 `idle_timeout - 心跳间隔` 内必须发出 `ping`,否则会被 server 主动 `close`)
|
||||
- **连接后错误帧(当前实现,非 HTTP 业务码)**:
|
||||
- JSON 无法解析:`event`=`ws.error`,`message`=`Invalid JSON payload`(无 `code` 或与 HTTP `code` 不同体系)
|
||||
- 未知 `action`:`event`=`ws.error`,`message`=`Unsupported action`,并可能带 `received_action`
|
||||
@@ -807,8 +820,10 @@
|
||||
#### 7.1.2 订阅行为说明
|
||||
|
||||
- **仅建立连接不会自动下发全部业务消息**;客户端需要发送 `subscribe` 明确订阅主题。
|
||||
- 成功订阅后服务端返回:`{"event":"ws.subscribed","topics":[...]}`。
|
||||
- 成功订阅后服务端返回:`{"event":"ws.subscribed","topics":[...]}`(已去重、按字典序排序,与提交顺序无关)。
|
||||
- **`subscribe` 覆盖式生效**:每次发送都会**完全替换**该连接的订阅集合(不是累加)。需要追加请把已有列表一并发上来。
|
||||
- 若未订阅主题,通常只能收到握手首帧(`ws.connected`)和心跳回包(`pong`)。
|
||||
- **服务端按 user_id 过滤**:mobile 模式连接只会收到 `data.user_id == 自己 user_id` 的 user 级主题(见 §7.0 列表);admin 模式不过滤,收到全量。**客户端仍应做一次防御性 `user_id` 过滤**,避免后续接口变更带来误处理。
|
||||
- **不下发** `streak_win_reward` 全表(1~10 档);赔率仅通过 `user.streak` / `wallet.changed` / `bet.accepted` 及 `lobbyInit.user_snapshot` 推送**当前登录玩家**本局适用字段。
|
||||
|
||||
#### 7.1.2A 连胜赔率与连胜场次(WebSocket)
|
||||
|
||||
Reference in New Issue
Block a user