# 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 编码已经对齐。 - 当前 WSS 版本会超时,是因为 Go 里的 WSS 外层协议模型不符合浏览器 JS。 ## 连接 - WebSocket URL:`wss:///?baseinfo=` - 手动 HAR host:`77bc035c-ws.va.huya.com` - host 来自 `launch.queryHttpDns` 或浏览器抓包,不应长期写死。 - 握手启用 `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 = "::0:" 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` - `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:///?baseinfo=`。 2. 发送 `EWSCmdC2S_HeartBeatReq`。 3. 通过 WSS 调用 `launch.wsLaunch`。 4. `wsLaunch` 后触发 `sendWSUpdateUserInfoReq`。 5. `launch.queryHttpDns` 仍通过 HTTP `cdnws` 调用。 6. 后续 WUP 业务在连接可用时走 `signalSdk.sendWup`,连接不可用时可 fallback 到 `sendWupHttp`。 响应应按 WUP `iRequestId` 匹配回调,不能只用 FIFO。 ## 活动接口 当前 Go HTTP 版本已实现: - `webActUI.getActPrizeList` - `webActUI.getUserScore` - `webActUI.getUserPrizeRecords` - `webActUI.scoreExchangePrize` WSS 版本仍是实验状态,需要按 `WebSocketCommand` 结构重写。 抢购兑换请求结构: ```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=兑换奖品:套装-潮萌小黄鸭` ## 待完善 - 实现 TAF `WebSocketCommand` 编解码。 - WSS WUP response 按 `iRequestId` 匹配请求。 - 实现 `WSUpdateUserInfoReq`、心跳、verify cookie 等浏览器初始化步骤。 - 自动调用 `launch.queryHttpDns` 获取最新 WSS host。 - 增加基于真实抓包样本的 WSS 编解码单测。