如何让所有异常都经过FastAPI中间件处理?
问题
使用FastAPI开发应用时,希望通过统一的中间件(按异常类型用不同except块)处理所有抛出的异常,尝试编写了如下中间件:
from fastapi import APIRouter, FastAPI, Request, HTTPException, Response, status from starlette.middleware.base import BaseHTTPMiddleware from fastapi.responses import JSONResponse class ExceptionHandlerMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): try: return await call_next(request) except HTTPException as e: return JSONResponse(status_code=e.status_code, content={'message': e.detail}) except Exception as e: return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={'message': str(e)}) # app creation and config go here.... app.add_middleware(ExceptionHandlerMiddleware)
但问题在于,HTTPException这类被FastAPI默认处理的异常,会在到达中间件前就被默认处理器拦截,无法进入中间件的except块。FastAPI文档提供的重写特定异常默认行为的方式繁琐且扩展性差,希望找到无需装饰器、全局强制所有异常都经过中间件处理的方法。
解决方案
要让所有异常都流经你的中间件,核心是移除FastAPI默认注册的异常处理器,这样异常就不会被提前拦截,而是传递到中间件的try/except块中。
步骤1:移除默认异常处理器
FastAPI默认会为HTTPException和RequestValidationError(对应422参数验证错误)注册专属处理器,需要先把它们从应用的异常处理器字典中移除:
from fastapi import RequestValidationError # 创建应用实例 app = FastAPI() # 移除默认的HTTPException处理器 app.exception_handlers.pop(HTTPException) # 移除默认的RequestValidationError处理器(处理422错误) app.exception_handlers.pop(RequestValidationError)
步骤2:保留中间件并调整异常捕获逻辑
此时你的中间件就能捕获到所有异常,包括原来被默认处理的HTTPException和参数验证异常。如果需要统一处理RequestValidationError,可以在中间件中新增对应的except块:
class ExceptionHandlerMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): try: return await call_next(request) except HTTPException as e: return JSONResponse(status_code=e.status_code, content={'message': e.detail}) except RequestValidationError as e: # 自定义参数验证错误的返回格式 error_details = [{'loc': err['loc'], 'msg': err['msg'], 'type': err['type']} for err in e.errors()] return JSONResponse( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, content={'message': '参数验证失败', 'errors': error_details} ) except Exception as e: return JSONResponse( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={'message': '服务器内部错误', 'detail': str(e)} ) # 添加中间件 app.add_middleware(ExceptionHandlerMiddleware)
关键说明
- 移除默认处理器后,所有未被捕获的异常都会传递到中间件的
try/except流程中,完全由你统一控制返回格式。 - 这种方式无需使用任何装饰器,仅通过修改应用配置和中间件即可实现全局异常统一处理。
- 若需要处理其他自定义异常,只需在中间件中新增对应的
except块即可,扩展性强。
内容的提问来源于stack exchange,提问作者TheMemeMachine
相关产品推荐
相关产品推荐

