124 lines
10 KiB
Markdown
124 lines
10 KiB
Markdown
# 虎牙精英宝典后端与 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. 补齐只读协议方法和响应结构
|
||
|
||
优先实现并测试:
|
||
|
||
```text
|
||
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. 重写兑换状态机
|
||
|
||
严格按以下顺序:
|
||
|
||
```text
|
||
实时 getActPrizeDetail
|
||
-> 校验 isCanExchange/活动时间/库存/今日限制/用户限制/可用积分
|
||
-> scoreExchangePrize
|
||
-> getUserScore + getUserPrizeRecords
|
||
-> getEntityPrizeFieldMap + getModuleAddress
|
||
```
|
||
|
||
成功、已兑换、余额不足、库存不足、需要地址和未知错误分别落库;收到成功响应后使用幂等键阻止重复提交。只有四项回查完成,任务才标记为兑换完成。
|
||
|
||
### 6. 重写开通和支付状态机
|
||
|
||
严格按以下顺序:
|
||
|
||
```text
|
||
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` 的显式前置调用;按账号隔离商品快照。
|