feat(backend): 重构 HTTP 错误处理为 RFC7807 标准并优化多个 service
This commit is contained in:
+37
-1
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import AsyncGenerator
|
||||
from typing import Any, AsyncGenerator
|
||||
|
||||
from fastapi import FastAPI, HTTPException, Request
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
@@ -11,6 +11,7 @@ from pydantic import BaseModel
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
|
||||
from core.config.settings import config
|
||||
from core.http.errors import ApiProblemError
|
||||
from core.http.response import build_problem_details
|
||||
from core.logging import configure_logging, get_logger, log_service_banner
|
||||
from services.base import close_registered_services, initialize_registered_services
|
||||
@@ -79,6 +80,19 @@ def _build_http_error_response(
|
||||
) -> JSONResponse:
|
||||
instance = request.url.path
|
||||
detail_text = detail if isinstance(detail, str) else "Request failed"
|
||||
error_code: str | None = None
|
||||
error_params: dict[str, Any] | None = None
|
||||
|
||||
if isinstance(detail, dict):
|
||||
raw_detail = detail.get("detail")
|
||||
raw_code = detail.get("code")
|
||||
raw_params = detail.get("params")
|
||||
if isinstance(raw_detail, str) and raw_detail.strip():
|
||||
detail_text = raw_detail
|
||||
if isinstance(raw_code, str) and raw_code.strip():
|
||||
error_code = raw_code
|
||||
if isinstance(raw_params, dict):
|
||||
error_params = raw_params
|
||||
logger.warning(
|
||||
"HTTP error",
|
||||
status_code=status_code,
|
||||
@@ -91,6 +105,8 @@ def _build_http_error_response(
|
||||
status_code=status_code,
|
||||
detail=detail_text,
|
||||
instance=instance,
|
||||
code=error_code,
|
||||
params=error_params,
|
||||
)
|
||||
return JSONResponse(
|
||||
status_code=status_code,
|
||||
@@ -170,3 +186,23 @@ async def unhandled_exception_handler(
|
||||
content=problem.model_dump(),
|
||||
media_type="application/problem+json",
|
||||
)
|
||||
|
||||
|
||||
@app.exception_handler(ApiProblemError)
|
||||
async def api_problem_exception_handler(
|
||||
request: Request,
|
||||
exc: ApiProblemError,
|
||||
) -> JSONResponse:
|
||||
instance = request.url.path
|
||||
problem = build_problem_details(
|
||||
status_code=exc.status_code,
|
||||
detail=exc.detail,
|
||||
instance=instance,
|
||||
code=exc.code,
|
||||
params=exc.params,
|
||||
)
|
||||
return JSONResponse(
|
||||
status_code=exc.status_code,
|
||||
content=problem.model_dump(),
|
||||
media_type="application/problem+json",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user