Fix remote browser JSON control-plane delivery

This commit is contained in:
genz27
2026-03-29 18:49:16 +08:00
parent cbf9cd1038
commit f3eb69308d
4 changed files with 30 additions and 12 deletions

View File

@@ -1,6 +1,7 @@
"""Admin API routes"""
import asyncio
import json
import httpx
from fastapi import APIRouter, Depends, HTTPException, Header, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel
@@ -189,7 +190,6 @@ async def _sync_json_http_request(
request_kwargs: Dict[str, Any] = {
"headers": req_headers,
"timeout": timeout,
"impersonate": "chrome120",
}
if payload is not None:
@@ -198,7 +198,9 @@ async def _sync_json_http_request(
request_kwargs["json"] = payload
try:
async with AsyncSession() as session:
# remote_browser 控制面是服务间 JSON API使用 httpx 避免 curl_cffi 在当前
# Windows + impersonate 场景下 POST body 丢失导致 FastAPI 直接判定 body 缺失。
async with httpx.AsyncClient(follow_redirects=True) as session:
response = await session.request(
method=request_method,
url=url,

View File

@@ -2,6 +2,7 @@
import asyncio
import json
import contextvars
import httpx
import time
import uuid
import random
@@ -2040,7 +2041,6 @@ class FlowClient:
request_kwargs: Dict[str, Any] = {
"headers": req_headers,
"timeout": timeout,
"impersonate": "chrome120",
}
if payload is not None:
@@ -2049,7 +2049,9 @@ class FlowClient:
request_kwargs["json"] = payload
try:
async with AsyncSession() as session:
# remote_browser 控制面只需要稳定传输 JSON不需要浏览器指纹伪装。
# 使用 httpx 可以避免 curl_cffi 在当前环境下 POST body 被吞掉。
async with httpx.AsyncClient(follow_redirects=True) as session:
response = await session.request(
method=request_method,
url=url,

View File

@@ -85,7 +85,7 @@ def test_flexible_auth_accepts_x_goog_api_key(monkeypatch):
) == "secret"
def test_admin_remote_browser_helper_uses_asyncsession(monkeypatch):
def test_admin_remote_browser_helper_uses_httpx(monkeypatch):
calls = []
class FakeResponse:
@@ -95,7 +95,10 @@ def test_admin_remote_browser_helper_uses_asyncsession(monkeypatch):
def json(self):
return {"success": True, "token": "abc"}
class FakeSession:
class FakeAsyncClient:
def __init__(self, **kwargs):
calls.append({"client_kwargs": kwargs})
async def __aenter__(self):
return self
@@ -110,7 +113,7 @@ def test_admin_remote_browser_helper_uses_asyncsession(monkeypatch):
})
return FakeResponse()
monkeypatch.setattr(admin_module, "AsyncSession", FakeSession)
monkeypatch.setattr(admin_module.httpx, "AsyncClient", FakeAsyncClient)
status_code, payload, response_text = asyncio.run(
admin_module._sync_json_http_request(
@@ -126,6 +129,11 @@ def test_admin_remote_browser_helper_uses_asyncsession(monkeypatch):
assert payload == {"success": True, "token": "abc"}
assert response_text == '{"success": true, "token": "abc"}'
assert calls == [
{
"client_kwargs": {
"follow_redirects": True,
},
},
{
"method": "POST",
"url": "https://example.com/api/v1/custom-score",
@@ -136,7 +144,6 @@ def test_admin_remote_browser_helper_uses_asyncsession(monkeypatch):
"Content-Type": "application/json; charset=utf-8",
},
"timeout": 15,
"impersonate": "chrome120",
"json": {"website_url": "https://example.com"},
},
}

View File

@@ -49,7 +49,7 @@ def test_control_plane_calls_use_short_timeouts(monkeypatch):
assert [call["timeout"] for call in calls] == [10, 15, 10, 10]
def test_remote_browser_http_helper_uses_asyncsession(monkeypatch):
def test_remote_browser_http_helper_uses_httpx(monkeypatch):
calls = []
class FakeResponse:
@@ -59,7 +59,10 @@ def test_remote_browser_http_helper_uses_asyncsession(monkeypatch):
def json(self):
return {"ok": True}
class FakeSession:
class FakeAsyncClient:
def __init__(self, **kwargs):
calls.append({"client_kwargs": kwargs})
async def __aenter__(self):
return self
@@ -74,7 +77,7 @@ def test_remote_browser_http_helper_uses_asyncsession(monkeypatch):
})
return FakeResponse()
monkeypatch.setattr(flow_client_module, "AsyncSession", FakeSession)
monkeypatch.setattr(flow_client_module.httpx, "AsyncClient", FakeAsyncClient)
status_code, payload, response_text = asyncio.run(
FlowClient._sync_json_http_request(
@@ -90,6 +93,11 @@ def test_remote_browser_http_helper_uses_asyncsession(monkeypatch):
assert payload == {"ok": True}
assert response_text == '{"ok": true}'
assert calls == [
{
"client_kwargs": {
"follow_redirects": True,
},
},
{
"method": "POST",
"url": "https://example.com/api/v1/solve",
@@ -100,7 +108,6 @@ def test_remote_browser_http_helper_uses_asyncsession(monkeypatch):
"Content-Type": "application/json; charset=utf-8",
},
"timeout": 12,
"impersonate": "chrome120",
"json": {"project_id": "project-123"},
},
}