问题:外部 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。
104 lines
3.7 KiB
Python
104 lines
3.7 KiB
Python
"""虎牙传输选择:网页设备态齐全走 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"]
|