|
|
@@ -3,80 +3,52 @@ from fastapi.responses import JSONResponse
|
|
|
import httpx
|
|
|
from ..core.logger import get_logger
|
|
|
from ..core.config import settings
|
|
|
+from contextlib import asynccontextmanager
|
|
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
+# 1. 创建一个全局的 client (配置好超时和连接池)
|
|
|
+# limits: max_keepalive_connections 控制连接池大小
|
|
|
+http_client = httpx.AsyncClient(timeout=10.0, limits=httpx.Limits(max_keepalive_connections=20, max_connections=100))
|
|
|
|
|
|
@router.get("/scoring_config", summary="[代理] 获取评分配置")
|
|
|
async def proxy_get_scoring_config():
|
|
|
- """
|
|
|
- 转发请求到分数的获取配置接口
|
|
|
- """
|
|
|
target_url = settings.SCORE_SERVER_CONFIG_URL
|
|
|
- logger.info(f"正在代理 GET 请求到: {target_url}")
|
|
|
|
|
|
- async with httpx.AsyncClient() as client:
|
|
|
- try:
|
|
|
- # 发送请求给项目1
|
|
|
- resp = await client.get(target_url, timeout=10.0)
|
|
|
+ try:
|
|
|
+ # 2. 直接使用全局 client,不需要 async with
|
|
|
+ resp = await http_client.get(target_url)
|
|
|
|
|
|
- # 如果项目1返回错误状态码,抛出对应的 HTTPException
|
|
|
- if resp.status_code != 200:
|
|
|
- logger.error(f"项目1返回错误: {resp.status_code} - {resp.text}")
|
|
|
- raise HTTPException(
|
|
|
- status_code=resp.status_code,
|
|
|
- detail=resp.json().get("detail", "上游服务错误")
|
|
|
- )
|
|
|
-
|
|
|
- # 返回项目1的数据
|
|
|
- return resp.json()
|
|
|
-
|
|
|
- except httpx.RequestError as exc:
|
|
|
- logger.error(f"连接项目1失败: {exc}")
|
|
|
+ if resp.status_code != 200:
|
|
|
+ logger.error(f"项目1返回错误: {resp.status_code} - {resp.text}")
|
|
|
raise HTTPException(
|
|
|
- status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
|
|
- detail=f"无法连接到评分服务 (Project 1): {exc}"
|
|
|
+ status_code=resp.status_code,
|
|
|
+ detail=resp.json().get("detail", "上游服务错误")
|
|
|
)
|
|
|
+ return resp.json()
|
|
|
+
|
|
|
+ except httpx.RequestError as exc:
|
|
|
+ # ... 错误处理保持不变 ...
|
|
|
+ logger.error(f"连接项目1失败: {exc}")
|
|
|
+ raise HTTPException(status_code=503, detail=str(exc))
|
|
|
|
|
|
|
|
|
@router.put("/scoring_config", summary="[代理] 更新评分配置")
|
|
|
async def proxy_update_scoring_config(config_data: dict = Body(...)):
|
|
|
- """
|
|
|
- 转发请求到分数的更新配置接口
|
|
|
- """
|
|
|
target_url = settings.SCORE_SERVER_CONFIG_URL
|
|
|
- logger.info(f"正在代理 PUT 请求到: {target_url}")
|
|
|
|
|
|
- async with httpx.AsyncClient() as client:
|
|
|
- try:
|
|
|
- # 将前端传来的 json 原封不动转发给项目1
|
|
|
- resp = await client.put(target_url, json=config_data, timeout=10.0)
|
|
|
+ try:
|
|
|
+ # 2. 复用连接
|
|
|
+ resp = await http_client.put(target_url, json=config_data)
|
|
|
|
|
|
- # 处理项目1的响应
|
|
|
- if resp.status_code != 200:
|
|
|
- # 可能是 400 校验错误,或者是 500 内部错误
|
|
|
- error_detail = "上游服务错误"
|
|
|
- try:
|
|
|
- error_detail = resp.json().get("detail", error_detail)
|
|
|
- except:
|
|
|
- pass
|
|
|
+ if resp.status_code != 200:
|
|
|
+ # ... 错误处理保持不变 ...
|
|
|
+ raise HTTPException(status_code=resp.status_code, detail="Error")
|
|
|
|
|
|
- logger.warning(f"项目1拒绝更新: {resp.status_code} - {error_detail}")
|
|
|
- raise HTTPException(
|
|
|
- status_code=resp.status_code,
|
|
|
- detail=error_detail
|
|
|
- )
|
|
|
+ return JSONResponse(status_code=resp.status_code, content=resp.json())
|
|
|
|
|
|
- return JSONResponse(
|
|
|
- status_code=resp.status_code,
|
|
|
- content=resp.json()
|
|
|
- )
|
|
|
-
|
|
|
- except httpx.RequestError as exc:
|
|
|
- logger.error(f"连接项目1失败: {exc}")
|
|
|
- raise HTTPException(
|
|
|
- status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
|
|
- detail=f"无法连接到评分服务 (Project 1): {exc}"
|
|
|
- )
|
|
|
+ except httpx.RequestError as exc:
|
|
|
+ logger.error(f"连接项目1失败: {exc}")
|
|
|
+ raise HTTPException(status_code=503, detail=str(exc))
|