Files
huya-go/WSS_NOTES.md
T
2026-07-06 18:47:10 +08:00

143 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WSS 协议要点
本文件记录 2026-07-06 手动浏览器 HAR、页面 JS 和 Go 版本当前实现的复核结论。
## 抓包结论
手动浏览器链路是 HTTP + WSS 混合:
- 页面初始化、商品信息、HttpDNS 等有多条 `https://cdnws.api.huya.com/` POST。
- 浏览器同时建立了 3 条 `wss://77bc035c-ws.va.huya.com/` 连接。
- `scoreExchangePrize` 出现在 WSS 连接数据和静态 JS 中,没有出现在 `cdnws` POST 请求中。
- 当前 HTTP 版本可用,是因为 `webActUI` 的 WUP over HTTP 编码已经对齐。
- Go 版 WSS 已改为浏览器同款 `WebSocketCommand` 外层,仍需真实 Cookie 联调确认服务端返回。
## 连接
- WebSocket URL:`wss://<host>/?baseinfo=<base64 taf>`
- 手动 HAR host:`77bc035c-ws.va.huya.com`
- host 来自 `launch.queryHttpDns` 或浏览器抓包,不应长期写死。
- 手动 HAR 中 `baseinfo.cookie` 与 `traceId` 为空,cookie 通过后续 `VerifyCookie` 命令发送。
- 握手启用 `permessage-deflate`。
- 浏览器请求扩展:`permessage-deflate; client_max_window_bits`
- 服务端返回扩展:`permessage-deflate;server_no_context_takeover;client_no_context_takeover`
## 正确外层结构
浏览器 JS 不是 `1B version + 1B command + 4B sequence + body`。
页面实际构造 TAF/JCE `WebSocketCommand`:
```text
WebSocketCommand {
0: iCmdType int32
1: vData bytes
2: lRequestId int64
3: traceId string
4: iEncryptType int32
5: lTime int64
6: sMD5 string
}
```
WUP 请求发送逻辑:
```text
Wup.setServant(servant)
Wup.setFunc(func)
Wup.setRequestId(requestId)
Wup.writeStruct("tReq", req)
WebSocketCommand.iCmdType = EWSCmd_WupReq(3)
WebSocketCommand.vData = Wup.encode()
WebSocketCommand.traceId = "<trace>:<trace>:0:<enableTrace>"
ws.send(WebSocketCommand.writeTo(JceOutputStream))
```
服务端返回 `EWSCmd_WupRsp(4)`,内部 `vData` 才是 WUP 响应。
## 命令枚举
页面 JS 中可见的关键枚举:
- `3`:`EWSCmd_WupReq`
- `4`:`EWSCmd_WupRsp`
- `5`:`EWSCmdC2S_HeartBeat`
- `6`:`EWSCmdS2C_HeartBeatAck`
- `10`:`EWSCmdC2S_VerifyCookieReq`
- `11`:`EWSCmdS2C_VerifyCookieRsp`
- `16`:`EWSCmdC2S_RegisterGroupReq`
- `17`:`EWSCmdS2C_RegisterGroupRsp`
- `20`:`EWSCmdC2S_HeartBeatReq`
- `21`:`EWSCmdS2C_HeartBeatRsp`
- `23`:`EWSCmdC2S_UpdateUserExpsReq`
- `24`:`EWSCmdS2C_UpdateUserExpsRsp`
- `33`:`EWSCmdC2S_UpdateUserInfoReq`
- `34`:`EWSCmdS2C_UpdateUserInfoRsp`
手动 HAR 解出的服务端 WSS 回包包括:
- `EWSCmdS2C_HeartBeatRsp`
- `EWSCmd_WupRsp launch.wsLaunch`
- `EWSCmd_WupRsp mobileui.getConfig`
- `EWSCmd_WupRsp webActUI.getActPrizeList`
- `EWSCmd_WupRsp webActUI.getUserScore`
- `EWSCmd_WupRsp webActUI.scoreExchangePrize`
## 初始化流程
浏览器 WSS session 的关键流程:
1. 连接 `wss://<host>/?baseinfo=<base64 taf>`。
2. 发送 `EWSCmdC2S_RegisterGroupReq(16)`,默认 group 为 `live:0`。
3. 通过 WSS 调用 `launch.wsLaunch`,手动 HAR 中 requestId 为 `-1`。
4. 发送 `EWSCmdC2S_VerifyCookieReq(10)`,cookie 在这里进入 WSS 通道。
5. 通过 WSS 调用 `mobileui.getConfig`。
6. 发送 `EWSCmdC2S_UpdateUserExpsReq(23)`,请求体是空 map。
7. 再发送一次 `EWSCmdC2S_RegisterGroupReq(16)`。
8. 发送 `EWSCmdC2S_HeartBeatReq(20)`,后续维持心跳。
9. `launch.queryHttpDns` 仍通过 HTTP `cdnws` 调用。
10. 后续 WUP 业务在连接可用时走 `signalSdk.sendWup`,连接不可用时可 fallback 到 `sendWupHttp`。
响应应按 WUP `iRequestId` 匹配回调,不能只用 FIFO。
## 活动接口
当前 Go HTTP 版本已实现:
- `webActUI.getActPrizeList`
- `webActUI.getUserScore`
- `webActUI.getUserPrizeRecords`
- `webActUI.scoreExchangePrize`
WSS 版本仍是实验状态,但外层 `WebSocketCommand`、初始化帧顺序和 requestId 匹配已按手动 HAR 修正。
抢购兑换请求结构:
```text
tReq.user
tReq.sid
tReq.pid
tReq.ip = ""
tReq.clientEnv = {}
tReq.source = ""
tReq.isRole = 1
```
浏览器手动抢购小黄鸭成功回包确认:
- `webActUI.scoreExchangePrize`
- `sid=2203`
- `pid=12889`
- `status=200`
- `msg=请求成功`
- `exchangeInfo.pid=12889`
- `exchangeInfo.exchangeScore=988`
- `exchangeInfo.desc=兑换奖品:套装-潮萌小黄鸭`
## 待完善
- 使用真实 Cookie 联调 `list/score/exchange`,确认服务端不再超时。
- 自动调用 `launch.queryHttpDns` 获取最新 WSS host。
- 补更多基于真实抓包摘要的 WSS 编解码单测。