10 KiB
虎牙精英宝典后端与 9.1 全流程抓包对照
结论
当前后端不是“完全不能用”,而是保留了旧版 HTTP/WUP 兜底链路;最新浏览器链路已经切换为两个长连接 WSS:活动/绑定通道和商城/支付通道。查询和下单的多数字段与抓包兼容,真正需要优先更新的是兑换闭环、支付后订单状态和权益回查。
对照矩阵
| 优先级 | 领域 | 9.1 实际链路 | 当前后端 | 判断 | 更新动作 |
|---|---|---|---|---|---|
| P0 | 支付监听 | orderDetailV5(orderId) 重复查询,状态最终为 50 |
queryUserOrderList,同时尝试 shopMiddleUI/revenueWebUI |
不一致 | 增加 orderDetailV5 结构和方法,按订单号轮询;以订单状态 50/已支付时间作为完成依据 |
| P0 | 支付超时 | 未支付仍是待支付/取消状态 | huya_runner_recharge.py:535-537 将 timeout 标为 success |
业务错误 | 超时改为 pending 或 timeout,不能写成功;前端显示“等待支付超时” |
| P0 | WSS 会话 | 活动通道 d35bf373-ws.va.huya.com,商城通道 wsapi.huya.com;每个会话有 launch、register、confirm、递增 requestId |
HuyaBatchRunner 全部调用 HuyaHttpClient 的 cdnws.api.huya.com 单次 HTTP |
架构不一致 | 优先实现可复用的 WSS session;HTTP 保留为显式 fallback,并记录 fallback 原因和重试次数 |
| P1 | 商城身份字段 | 最新商城业务 UserId.sHuYaUA=web&1.0.0&huya,sGuid 为空 |
HTTP _build_user 使用 webh5&0.0.1&websocket...,并从 Cookie 派生 sGuid |
字段不一致 | 商城 WSS 优先;HTTP fallback 也应拆分商城 UserId,按最新 UA/空 guid 构造 |
| P1 | 兑换前置 | getActPrizeDetail(sid=2203,pid),随后才 scoreExchangePrize |
huya_runner_goods.py:327-329 直接提交兑换 |
缺步骤 | 增加 GetActPrizeDetailReq/Resp;提交前校验 isCanExchange、活动时间、库存、今日/用户限制和积分余额 |
| P1 | 兑换回查 | 成功后依次回查 getUserScore、getUserPrizeRecords、getEntityPrizeFieldMap、getModuleAddress |
成功后立即结束任务 | 缺步骤 | 将扣分、记录和地址状态写入任务结果,并更新 HuyaAccount.points |
| P1 | 活动初始化 | getActInfo、getActUserTaskDetail、getUserScore、getUserPrizeRecords 等并行查询 |
query_act_tasks 只调用 getActTaskDetail |
信息不完整 | 增加 snapshot 任务或让页面初始化批量创建这些查询任务 |
| P1 | 权益到账 | 支付完成后仍需回查宝典积分/用户任务 | 只回查商城订单列表 | 信息不完整 | 订单完成后调用积分和用户任务接口,明确“已支付”和“宝典权益到账”两个状态 |
| P2 | 商品详情 | getGoodsInfoV5 直接返回 spu=hy-5879340、sku=5370360、场景 4 |
当前会先从任务详情发现 SPU,再以 sku=0 查询详情 | 兼容但脆弱 | 固定业务默认值仅作候选;优先使用实时商品详情返回的 SKU,不依赖任务类型 67 |
| P2 | 商品详情 gameId | 最新 getGoodsInfoV5 请求的 gameId 为空字符串 |
huya_runner_recharge.py:385-395 传入 game_id="0" |
细节不一致 | 查询商品详情改为空字符串;createOrderV5 的 gameId="0" 仍保持不变 |
| P2 | 下单字段 | orderType=6、src=4、orderScene=4、bizType=5、gameCategoryId=507、gameId="0" |
create_order 已按相同字段写入 |
基本一致 | 保留,增加请求快照脱敏日志以便字段回归 |
| P2 | 支付提交 | payOrderSubmitV5(order,Zfb,QrCode,callback,env) 返回支付宝网关 URL |
当前 HTTP 手工构造 WUP,字段基本一致 | 兼容但非同链路 | 迁移到商城 WSS;未迁移前保留 HTTP fallback |
| P2 | 支付渠道 | 先 listPayChannelV5,返回 Zfb/Weixin |
直接使用配置渠道 | 缺运行时校验 | 下单前读取可用渠道,不支持配置值时回退或报错 |
| P2 | 配置 | 本次活动 sid=2203、绑定活动 9271、外部活动响应为 17096 |
outer_act_id 默认 9504 且执行器未实际使用 |
配置过期/死字段 | 默认值改为当前活动值或删除该字段;将外部活动 ID 从 getLiveLinkParam 响应传递,不手填签名 |
| P2 | 数据隔离 | 业务响应随账号、绑定状态和库存变化 | HuyaGoodsSnapshot、HuyaRechargeGoodsSnapshot 为全局快照 |
并发风险 | 至少按 sid/spu 隔离;兑换可用性必须以执行账号的实时查询为准 |
已对上的部分
ActivityUserId的lUid、sHuYaUA、Cookie 前缀和空 Token 形态与 9.1 活动帧兼容。scoreExchangePrize的主体字段userId/sid/pid/ip/clientEnv/source/isRole已有结构,样本中后三项为空、isRole=1与默认值一致。- 商城
CreateOrderReqV5已覆盖抓包中的完整 tag 0-32;orderType=6和场景 4 正确。 payOrderSubmitV5的回调 URL、Zfb、QrCode和环境 map 已覆盖抓包字段。CreateOrderReqV5的下单gameId="0"与抓包一致;只有商品详情查询的gameId应为空字符串。- Cookie、baseinfo、WUP requestId、支付宝订单和签名没有被当作固定常量,方向正确。
推荐更新顺序(按依赖关系)
之前的顺序有两个问题:把支付状态修复放在协议补齐之前,且把 WSS 迁移放在写操作之后。这样会先扩大旧链路的行为面,无法判断是业务字段还是传输方式导致失败。建议按下面的依赖顺序推进,每一步都能独立验证和回滚。
0. 固化 9.1 契约和回归样本
整理脱敏的请求/响应 fixture,明确活动通道、商城通道、WUP tag、状态码和动态字段边界。先不改线上任务行为,只增加解码测试。验收条件:9.1 中的关键 RPC 能稳定解码,动态 Cookie、签名、订单号不会进入 fixture。
1. 先修配置和身份模型
将 sid=2203、bindActId=9271、outerActId=17096、moduleId=20051、scene=4、sourceId=yellowcarlist 统一为活动配置;商城 UserId 与活动 UserId 分开,商城使用最新 sHuYaUA/空 sGuid 规则。此步只影响参数构造,不启用新写操作。
2. 补齐只读协议方法和响应结构
优先实现并测试:
getActInfo
getActUserTaskDetail
getActPrizeDetail
getEntityPrizeFieldMap
getModuleAddress
listPayChannelV5
orderDetailV5
只读方法齐全后,才能用服务端实时数据做兑换和支付前置判断;不要先改 scoreExchangePrize 或支付提交。
3. 建立统一传输层,再做只读灰度
抽象活动 WSS session 和商城 WSS session,复用 launch/register/confirm、requestId FIFO、断线和超时处理。先让查询接口走 WSS,失败时明确记录原因并 fallback 到 HTTP;连续验证成功后再切换写接口。不要在每个 runner 中分别临时建 WebSocket。
4. 先做快照和数据隔离
页面初始化改为一次读取活动信息、用户任务、积分、奖品和记录;商品/充值商品快照至少按 sid + spu/pid 隔离,执行账号始终以实时详情覆盖快照。此步完成后 UI 可以展示真实状态,但仍不触发兑换或支付。
5. 重写兑换状态机
严格按以下顺序:
实时 getActPrizeDetail
-> 校验 isCanExchange/活动时间/库存/今日限制/用户限制/可用积分
-> scoreExchangePrize
-> getUserScore + getUserPrizeRecords
-> getEntityPrizeFieldMap + getModuleAddress
成功、已兑换、余额不足、库存不足、需要地址和未知错误分别落库;收到成功响应后使用幂等键阻止重复提交。只有四项回查完成,任务才标记为兑换完成。
6. 重写开通和支付状态机
严格按以下顺序:
getGoodsInfoV5
-> listPayChannelV5
-> checkHyProtocolV5 / checkUserBuyAuth
-> createOrderV5(orderType=6)
-> payOrderSubmitV5(Zfb|Weixin, QrCode)
-> 立即 orderDetailV5 轮询
-> 支付完成后回查宝典积分和用户任务
orderDetailV5 必须先于 runner 改造完成;queryUserOrderList 只能作为兼容 fallback。支付状态拆成 created/pending/paid/timeout/cancelled/error,超时绝不能标记 success。二维码生成后任务保持 running/pending,不能因为 runner 线程尚未结束而隐藏二维码。
7. 最后接入 UI 和批量执行
UI 只调用统一任务 API:查询使用快照任务,兑换和开通使用状态机任务;通过任务 WebSocket 推送二维码、订单状态和最终权益状态。先单账号灰度,再开启并发批量,避免旧的全局商品快照污染多个账号。
8. 清理旧链路
连续灰度验证通过后,删除 create_order 的 orderType 猜测和支付列表轮询主路径;保留 HTTP fallback、失败原因、超时和回滚开关。最后再迁移旧版虎牙任务入口,避免影响非精英宝典功能。
不应照搬抓包的字段
UID、Cookie、guid、baseinfo、WUP requestId、支付宝 payOrderId、ctoken、二维码 URL、t/code/sig、用户点击时间和 RSA2 签名均为运行时动态值。它们只能来自当前登录态、前序响应或运行时生成,不能写入默认配置或测试 fixture。
本轮已实施
- 增加
getActInfo、getActUserTaskDetail、getActPrizeDetail和详情响应结构。 - 兑换提交前读取实时详情和积分,校验可兑换状态、库存、时间窗口和余额;成功后回查积分和兑换记录。
- 增加
orderDetailV5请求/响应结构,支付监听优先按订单号查询,旧订单列表作为 fallback。 - 支付超时改为终态
timeout,不再误报成功;支付完成后回查活动积分。 - 商城 HTTP fallback 的
UserId改为 9.1 商城 UA/空 guid 形态;商品详情gameId改为空字符串,下单仍使用gameId="0"。 - 外部活动默认值由旧值更新为
17096,已有旧配置会在读取时迁移。
仍待下一轮实施:将批处理执行器从 HTTP fallback 迁移到统一活动/商城 WSS session;补齐 listPayChannelV5、checkHyProtocolV5、getMyPromotion、calcOrderPromotion 和 checkUserBuyAuth 的显式前置调用;按账号隔离商品快照。