You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为FastAPI所有子应用统一处理自定义异常?

问题背景

我有一个包含多个子应用的FastAPI项目(示例仅包含一个子应用),代码如下:

main_app = FastAPI()

class CustomException(Exception):  
    def __init__(self, message: str, status_code: int, name: str = "Exception"):
        Exception.__init__(self)
        self.name = name
        self.status_code = status_code
        self.message = message

@main_app.exception_handler(CustomException)
async def custom_exception_handler(exception: CustomException) -> JSONResponse:
    return JSONResponse(
        status_code=exception.status_code, content={"error": exception.message}
    )
main_app.mount("/subapp", subapp1)  

我已在主应用中处理了异常,但未在subapp1中处理。当在subapp1中抛出CustomException时:

raise CustomException(
    status_code=status.HTTP_404_NOT_FOUND,
    message=f"{self.model.__name__} not found",
)

出现错误:

RuntimeError: Caught handled exception, but response already started.

可见在子应用中抛出CustomException时,无法被主应用的异常处理器处理,请问如何使用主应用的异常处理器统一处理所有子应用的异常?

解决方案

FastAPI通过mount挂载的子应用拥有独立的异常处理机制,主应用的异常处理器不会自动作用于子应用。要实现统一处理,有两种可行方式:

方式一:将主应用的异常处理器注册到所有子应用

先抽离出独立的异常处理器函数,再分别注册到主应用和所有子应用:

from fastapi import Request, JSONResponse

# 定义通用的异常处理器
async def custom_exception_handler(request: Request, exception: CustomException) -> JSONResponse:
    return JSONResponse(
        status_code=exception.status_code, content={"error": exception.message}
    )

# 注册到主应用
main_app.add_exception_handler(CustomException, custom_exception_handler)

# 注册到子应用
subapp1.add_exception_handler(CustomException, custom_exception_handler)
# 如有更多子应用,重复上述注册步骤即可

注意:异常处理器必须包含request参数——FastAPI要求异常处理器的第一个参数为Request对象,你之前的代码遗漏了该参数,这也是触发RuntimeError的核心原因之一。

方式二:通过中间件让主应用接管子应用异常

如果不想逐个给子应用注册处理器,可以自定义中间件捕获子应用的异常,重新抛出后交由主应用的处理器处理:

from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware

class SubAppExceptionMiddleware(BaseHTTPMiddleware):
    def __init__(self, app):
        super().__init__(app)

    async def dispatch(self, request: Request, call_next):
        try:
            return await call_next(request)
        except CustomException as exc:
            # 直接将异常抛回给主应用处理
            raise exc
        # 如需处理其他异常,可添加额外except分支

# 给子应用添加中间件
subapp1.add_middleware(SubAppExceptionMiddleware)

# 挂载子应用到主应用
main_app.mount("/subapp", subapp1)

这种方式通过中间件拦截子应用的异常,避免了重复注册处理器的操作,适合子应用数量较多的场景。

关键注意事项

  • 异常处理器必须包含request参数,否则FastAPI调用时会出现参数不匹配,导致响应启动后再抛出异常,触发RuntimeError。
  • 挂载的子应用是独立的ASGI实例,主应用的全局配置(包括异常处理器)不会自动继承,必须通过显式注册或中间件接管的方式实现统一处理。

内容的提问来源于stack exchange,提问作者Ghasem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 13:33:24