FastAPI中必须用app.add_exception_handler()显式注册全局异常处理器,传入异常类和签名固定的异步处理函数,返回JSONResponse;不能依赖装饰器或中间件,且需按具体到通用的顺序注册以避免覆盖内置处理器。

FastAPI中用add_exception_handler注册全局异常处理器
FastAPI不自动把未捕获的Python异常转成JSON响应,必须显式注册处理器。核心是调用app.add_exception_handler(),传入异常类和处理函数——不是装饰器写法,也不是中间件。
常见错误是试图用@app.exception_handler(...)装饰普通函数(这仅对HTTP异常有效),或在try/except里手动raise HTTPException,这无法覆盖ValueError、KeyError等原生异常。
-
add_exception_handler()必须在app = FastAPI()之后、uvicorn.run()之前调用 - 处理函数签名固定为
async def handler(request: Request, exc: Exception) -> JSONResponse - 不能返回
dict或Response,必须是JSONResponse(否则状态码可能被忽略)
处理Exception基类时注意覆盖顺序
FastAPI内部已注册了HTTPException和RequestValidationError的处理器,如果你用add_exception_handler(Exception, ...),它会生效,但必须放在所有其他add_exception_handler调用之后——否则会拦截掉原本该由内置处理器处理的异常。
典型陷阱:把Exception处理器写在最前面,结果422 Unprocessable Entity错误也变成500 Internal Server Error的JSON,丢失了字段校验细节。
立即学习“Python免费学习笔记(深入)”;
- 先注册具体异常(如
ValueError、DatabaseError),再注册Exception - 如果只想要“兜底”,就只注册
Exception,但要接受它会吞掉所有未显式声明的异常类型 - 处理函数里用
exc.__class__.__name__和str(exc)构造消息,别直接repr(exc)(含敏感路径)
JSONResponse的状态码和结构怎么设才合理
Python原生异常没有对应HTTP状态码,所以得自己映射。不能一律用500,比如ValueError("user_id must be positive")更适合400 Bad Request;数据库连接失败才用503 Service Unavailable。
返回结构建议保持和FastAPI默认错误一致:{"detail": "..."},而不是自创{"error": ..., "code": ...}——否则前端统一处理成本高。
- 用
status_code=500作为兜底,但对已知业务异常类型(如UserNotFound)显式设404 - 避免在响应体里暴露
exc.__traceback__(开发环境可加settings.DEBUG开关) - 示例:
from fastapi.responses import JSONResponse from fastapi import Request async def general_exception_handler(request: Request, exc: Exception): return JSONResponse( status_code=500, content={"detail": "Internal server error"}, )
异步异常(如await中抛出)是否需要特殊处理
不需要。FastAPI的异常处理器本身是异步函数,能正常捕获await语句中抛出的任何异常,包括async def路由函数内部、依赖注入函数里、甚至BackgroundTasks中同步抛出的异常(只要没被局部try/except吞掉)。
真正容易漏的是:在BackgroundTask里抛异常,不会触发全局处理器——因为任务已脱离当前请求生命周期。这类异常必须在任务内部try/except并记录日志。
- 所有
async def路由、依赖、Depends里的await都受全局处理器覆盖 -
BackgroundTask、线程池、信号处理器里的异常需单独兜底 - 若用
asyncpg等库,其连接异常(如asyncpg.exceptions.ConnectionDoesNotExistError)属于普通异常,走Exception处理器


















