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

4.4 KiB
Raw Blame History

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:

WebSocketCommand {
  0: iCmdType int32
  1: vData bytes
  2: lRequestId int64
  3: traceId string
  4: iEncryptType int32
  5: lTime int64
  6: sMD5 string
}

WUP 请求发送逻辑:

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 修正。

抢购兑换请求结构:

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 编解码单测。