Files
live-hub-py/tests/test_huya_http_shop_flow.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

96 lines
2.9 KiB
Python

"""HTTP cdnws 通道的下单/支付参数对齐(2026-10-13 积分中心抓包)。
外部 CK(只有登录态、无网页设备态)会走 HTTP 通道,因此 HTTP 侧的参数必须与
抓包一致:jifencenter 标记、空点击序列、m-shop.huya.com 回调、appInfo.scene 与
订单 src/orderScene 分离。
"""
from core.huya.http_client import HuyaHttpClient
def _recording_client():
client = HuyaHttpClient(logger=lambda _message: None)
recorded: list[tuple[str, str, object]] = []
def fake_call_rpc(
service, method, req_struct, rsp_class=None, uid=0, guid="", cookie="", **kwargs
):
recorded.append((service, method, req_struct))
client.call_rpc = fake_call_rpc # type: ignore[method-assign]
return client, recorded
def test_http_create_order_matches_points_capture():
client, recorded = _recording_client()
client.create_order(
uid=1199665170519,
guid="",
cookie="yyuid=1199665170519",
pid=1199650619883,
spu_id="hy-8328015",
sku_id=7756811,
)
service, method, req = recorded[-1]
assert (service, method) == ("shopMiddleUI", "createOrderV5")
assert req.shopAppInfo.scene == 7 # appInfo scene
assert req.src == 4 # 订单侧 scene
assert req.orderScene == 4
assert req.orderType == 6
assert req.extraParam.bizParams == '{ "jifencenter": 1 }'
assert req.env == {"user_click_seq": "[]"}
assert req.bizType == 5
assert req.gameCategoryId == 507
def test_http_get_goods_info_uses_app_scene():
client, recorded = _recording_client()
client.get_goods_info(
uid=1199665170519,
guid="",
cookie="yyuid=1199665170519",
pid=1199650619883,
spu_id="hy-8328015",
)
service, method, req = recorded[-1]
assert (service, method) == ("shopMiddleUI", "getGoodsInfoV5")
assert req.shopAppInfo.scene == 7
assert req.pid == 1199650619883
assert req.spuId == "hy-8328015"
def test_http_pay_order_submit_points_callback_and_env(monkeypatch):
captured: dict[str, bytes] = {}
class _StopAfterCapture(Exception):
pass
def fake_urlopen(request, timeout=None):
captured["body"] = request.data
raise _StopAfterCapture
monkeypatch.setattr("urllib.request.urlopen", fake_urlopen)
client = HuyaHttpClient(logger=lambda _message: None)
result = client.pay_order_submit(
uid=1199665170519,
guid="",
cookie="yyuid=1199665170519",
order_id=11339649,
pay_type="Zfb",
pid=1199650619883,
)
assert result is None # 捕获到请求即中断,不关心响应
body = captured["body"]
assert (
b"https://m-shop.huya.com/points.html#/consumer/paycallback"
b"?orderId=11339649&pid=1199650619883&sourceId=yellowcarlist"
) in body
assert b"user_click_seq" in body
assert b"input_1" not in body