from fastapi import FastAPI, Request, Response, WebSocket, WebSocketDisconnect import httpx import uvicorn import asyncio import websockets import logging import json app = FastAPI() TARGET_BASE = "http://127.0.0.1:9222" # Chrome DevTools HTTP 地址 TARGET_WS_BASE = "ws://127.0.0.1:9222" # Chrome DevTools WebSocket 地址 # 配置日志 logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"]) async def proxy(request: Request, path: str): url = f"{TARGET_BASE}/{path}" headers = dict(request.headers) headers["host"] = "127.0.0.1" # 强制修改 Host 头 body = await request.body() async with httpx.AsyncClient(follow_redirects=True) as client: resp = await client.request( request.method, url, headers=headers, content=body, params=request.query_params ) return Response( content=resp.content, status_code=resp.status_code, headers=dict(resp.headers) ) @app.websocket("/{path:path}") async def websocket_proxy(websocket: WebSocket, path: str): await websocket.accept() target_url = f"{TARGET_WS_BASE}/{path}" logger.info(f"Forwarding to: {target_url}") try: async with websockets.connect(target_url) as target_ws: # # 1. 先发送初始化命令(必需) # await target_ws.send(json.dumps({ # "id": 1, # "method": "Runtime.enable" # })) # logger.info("Sent Runtime.enable") # 2. 启动转发任务 async def forward_client_to_server(): try: while True: data = await websocket.receive_text() logger.info(f"CLIENT->CHROME: {data[:200]}") await target_ws.send(data) except WebSocketDisconnect: logger.info("Client disconnected") async def forward_server_to_client(): try: while True: response = await target_ws.recv() logger.info(f"CHROME->CLIENT: {response[:200]}") await websocket.send_text(response) except websockets.exceptions.ConnectionClosed: logger.info("Browser disconnected") await asyncio.gather( forward_client_to_server(), forward_server_to_client() ) except Exception as e: logger.error(f"Error: {e}") finally: await websocket.close() if __name__ == "__main__": uvicorn.run("fun:app", host="0.0.0.0", port=8000, reload=True)