from fastapi import FastAPI, Request, Response, WebSocket, WebSocketDisconnect import httpx import uvicorn import asyncio import websockets import logging app = FastAPI() TARGET_BASE = "http://127.0.0.1:9222" # Chrome DevTools HTTP 地址 TARGET_WS_BASE = "ws://127.0.0.1" # 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 WebSocket to: {target_url}") try: async with websockets.connect( target_url, extra_headers={"Host": "127.0.0.1"}, ping_timeout=30, close_timeout=10 ) as target_ws: async def client_to_server(): while True: data = await websocket.receive_bytes() # 支持二进制 await target_ws.send(data) async def server_to_client(): while True: data = await target_ws.recv() if isinstance(data, bytes): await websocket.send_bytes(data) else: await websocket.send_text(data) await asyncio.gather(client_to_server(), server_to_client()) except WebSocketDisconnect: logger.info("Client disconnected") except Exception as e: logger.error(f"WebSocket error: {e}") await websocket.close() if __name__ == "__main__": uvicorn.run("hg:app", host="0.0.0.0", port=8000, reload=True)