From 394c2f7229ab1b3e3e72a9892f398ae8b0eda73b Mon Sep 17 00:00:00 2001 From: shiyu Date: Mon, 8 Dec 2025 21:21:57 +0800 Subject: [PATCH] feat: enhance exception handling with additional handlers for HTTP and validation errors --- main.py | 14 ++++++++-- middleware/exception_handler.py | 47 ++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/main.py b/main.py index ba943b3..e04e8df 100644 --- a/main.py +++ b/main.py @@ -5,8 +5,15 @@ from fastapi.middleware.cors import CORSMiddleware from contextlib import asynccontextmanager from db.session import close_db, init_db from api.routers import include_routers -from fastapi import FastAPI -from middleware.exception_handler import global_exception_handler +from fastapi import FastAPI, HTTPException +from fastapi.exceptions import RequestValidationError +from middleware.exception_handler import ( + global_exception_handler, + http_exception_handler, + httpx_exception_handler, + validation_exception_handler, +) +import httpx from dotenv import load_dotenv from domain.tasks.task_queue import task_queue_service @@ -34,6 +41,9 @@ def create_app() -> FastAPI: lifespan=lifespan, ) include_routers(app) + app.add_exception_handler(HTTPException, http_exception_handler) + app.add_exception_handler(RequestValidationError, validation_exception_handler) + app.add_exception_handler(httpx.HTTPStatusError, httpx_exception_handler) app.add_exception_handler(Exception, global_exception_handler) return app diff --git a/middleware/exception_handler.py b/middleware/exception_handler.py index 06d1a76..73648b6 100644 --- a/middleware/exception_handler.py +++ b/middleware/exception_handler.py @@ -1,10 +1,49 @@ -from fastapi import Request, status +import logging +from fastapi import Request, status, HTTPException from fastapi.responses import JSONResponse +from fastapi.exceptions import RequestValidationError +import httpx + +logger = logging.getLogger(__name__) + + +async def http_exception_handler(request: Request, exc: HTTPException): + detail = exc.detail if exc.detail is not None else str(exc) + return JSONResponse( + status_code=exc.status_code, + content={"error": "HTTPException", "detail": detail}, + headers=exc.headers, + ) + + +async def validation_exception_handler(request: Request, exc: RequestValidationError): + return JSONResponse( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + content={"error": "Validation Error", "detail": exc.errors()}, + ) + + +async def httpx_exception_handler(request: Request, exc: httpx.HTTPStatusError): + resp = exc.response + status_code = resp.status_code if resp is not None else status.HTTP_500_INTERNAL_SERVER_ERROR + detail = None + if resp is not None: + detail = resp.text or resp.reason_phrase + if not detail: + detail = str(exc) + return JSONResponse( + status_code=status_code, + content={"error": "Upstream HTTP error", "detail": detail}, + ) + async def global_exception_handler(request: Request, exc: Exception): - """ - 全局异常处理 - """ + logger.exception( + "Unhandled exception %s %s", + request.method, + request.url.path, + exc_info=(type(exc), exc, exc.__traceback__), + ) return JSONResponse( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"error": "Internal Server Error", "detail": str(exc)},