mirror of
https://github.com/TheSmallHanCat/flow2api.git
synced 2026-06-02 04:41:36 +08:00
Fix remote browser JSON control-plane delivery
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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"},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user