Files
live-hub-py/tests/test_huya_runner_transport.py
T
yml2213 b5d8d5b5d8 feat(huya): 缺网页设备态的 CK 回退 HTTP cdnws 通道
问题:外部 CK(只带登录态)导入工作台后,任何任务都被「Cookie 缺少网页设备态
(sdid/udb_deviceid/udb_guiddata/udb_anobiztoken)」直接拦下,查询角色/开通都用不了。

实测结论(2026-10-15,同一张外部 CK):
- 这些字段是 WSS 通道的门禁,不是业务必需 —— 同一条 CK 走 HTTP cdnws 可以正常查询
  角色、商品,并走完整条开通链路(商品/小店/渠道/协议/返利/试算/同意/购买权限)
- A/B 对照(同一账号只抽掉 sdid):含 sdid 服务端回包,去掉即完全不回包,说明 sdid
  是 WSS 的硬门槛,而 HTTP 通道不需要
- 因此改为按能力选通道:设备态齐全走 WSS(行为不变),缺设备态回退 HTTP 并记日志

- http_client:补齐积分中心链路(get_supplier_info / accept_hy_protocol /
  calc_order_promotion / play_mall_get_my_promotion / play_mall_query_allocation /
  get_user_profile / get_follow_wechat_status);下单与支付参数对齐 2026-10-13 抓包
  (appInfo.scene=7、订单 src/orderScene=4、orderType=6、jifencenter 标记、空点击序列、
  m-shop.huya.com/points.html 回调),并去掉 orderType 1→10 的重试循环(有重复下单风险)
- huya_runner_core:_activity_client/_shop_client 不再抛 COOKIE_INCOMPLETE,改为
  返回 HTTP cdnws 客户端(方法签名与 WSS 会话保持一致,任务侧无感)

验证:tests/test_huya_http_shop_flow.py(下单/支付参数与回调域名)、
tests/test_huya_runner_transport.py(通道选择:缺设备态走 HTTP、齐全仍走 WSS);
真机 HTTP 开通链路 8 步全通(末步服务端返回业务提示「已超过该商品的购买上限」,
说明通道可用而非被丢弃)。反向验证:关掉回退即复现原报错。全量 pytest 717 passed。
2026-10-15 15:21:51 +08:00

104 lines
3.7 KiB
Python
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,缺设备态回退 HTTP cdnws。
背景(2026-10-15 实测,外部 CK 导入后):只带登录态、缺 sdid/udb_deviceid/
udb_guiddata/udb_anobiztoken 的 Cookie 在 WSS 上会被服务端静默丢弃业务请求
(wsLaunch / 业务 RPC 无响应),同一条 Cookie 走 HTTP cdnws 通道可正常查询。
"""
from core.huya.http_client import HuyaHttpClient
from web.backend.services.huya_runner_core import HuyaBatchRunnerCore
LOGIN_ONLY_COOKIE = (
"udb_cred=cred; udb_biztoken=biz; udb_uid=1199659425268; yyuid=1199659425268"
)
COMPLETE_COOKIE = (
"udb_cred=cred; udb_biztoken=biz; udb_uid=1199659425268; yyuid=1199659425268; "
"sdid=sdid; udb_deviceid=w_1234567890123456789; udb_guiddata=guiddata; "
"udb_anobiztoken=anobiz"
)
def _runner() -> HuyaBatchRunnerCore:
# 这两个方法只用 db 无关的状态,直接构造即可
return HuyaBatchRunnerCore(
db=None, batch_id="test-batch", task_type="query_game_name"
)
def test_minimal_app_cookie_reports_only_missing_web_guid():
cookie = (
"udb_cred=cred; udb_biztoken=biz; udb_uid=1199659425268; "
"yyuid=1199659425268; sdid=sdid"
)
assert HuyaBatchRunnerCore._web_wss_cookie_missing(cookie) == (
"udb_deviceid",
"udb_guiddata",
"udb_anobiztoken",
)
assert not HuyaBatchRunnerCore._has_web_wss_cookie(cookie)
def test_complete_web_cookie_enables_wss_without_logging_values():
cookie = (
"udb_cred=cred; udb_biztoken=biz; udb_uid=1199659425268; "
"yyuid=1199659425268; sdid=sdid; guid=0123456789abcdef0123456789abcdef; "
"udb_guiddata=guiddata; udb_deviceid=w_1234567890123456789; game_did=game; "
"_qimei_uuid42=qimei; udb_anobiztoken=anobiz; __yamid_new=yamid"
)
assert HuyaBatchRunnerCore._web_wss_cookie_missing(cookie) == ()
assert HuyaBatchRunnerCore._has_web_wss_cookie(cookie)
def test_script_only_fields_do_not_block_wss():
"""guid/_qimei_uuid42/__yamid_new/game_did 无服务端签发时不再阻断 WSS。"""
cookie = (
"udb_cred=cred; udb_biztoken=biz; udb_uid=1199659425268; "
"yyuid=1199659425268; sdid=sdid; "
"udb_deviceid=w_1234567890123456789; udb_guiddata=guiddata; "
"udb_anobiztoken=anobiz"
)
assert HuyaBatchRunnerCore._web_wss_cookie_missing(cookie) == ()
assert HuyaBatchRunnerCore._has_web_wss_cookie(cookie)
def test_login_only_cookie_falls_back_to_http_channel():
"""缺网页设备态不再抛 COOKIE_INCOMPLETE,改用 HTTP cdnws 客户端。"""
runner = _runner()
activity = runner._activity_client(1199659425268, LOGIN_ONLY_COOKIE)
shop = runner._shop_client(1199659425268, LOGIN_ONLY_COOKIE)
assert isinstance(activity, HuyaHttpClient)
assert isinstance(shop, HuyaHttpClient)
# HTTP 客户端具备任务侧需要的同名方法(含新增的积分中心 RPC)
for method in (
"check_user_bind_game_account",
"get_act_task_detail",
"query_user_score",
"get_goods_info",
"get_supplier_info",
"accept_hy_protocol",
"calc_order_promotion",
"create_order",
"pay_order_submit",
):
assert callable(getattr(activity, method)), method
def test_complete_cookie_keeps_using_wss(monkeypatch):
opened: list[str] = []
def fake_open(self, uid: int, cookie: str, kind: str):
opened.append(kind)
return f"wss-{kind}"
monkeypatch.setattr(HuyaBatchRunnerCore, "_open_wss_session", fake_open)
runner = _runner()
assert runner._activity_client(1199659425268, COMPLETE_COOKIE) == "wss-activity"
assert runner._shop_client(1199659425268, COMPLETE_COOKIE) == "wss-shop"
assert opened == ["activity", "shop"]