FastAPI中exception_handler和middleware 的执行顺序

在 FastAPI 中,exception_handler 和 middleware 的执行顺序是一个常见的问题。理解它们的执行顺序对于正确处理请求和异常非常重要。

1.源码分析

查看starlette.applications.Starlette类的构造方法,可以看到异常处理器和中间件的类型: 查看源码中添加中间件、异常处理器、路由的逻辑:

查看源码中构建应用的中间件栈的方法:

这个函数 build_middleware_stack 是一个用于构建 ASGI(Asynchronous Server Gateway Interface)应用的中间件栈的方法。ASGI 是一种异步 Web 服务器与异步 Web 应用或框架之间的接口标准。中间件是位于应用和服务器之间的组件,可以处理请求和响应,通常用于日志记录、身份验证、错误处理等。

逐步解释

  1. 定义函数和初始化变量:

    python 复制代码
    def build_middleware_stack(self) -> ASGIApp:
        debug = self.debug
        error_handler = None
        exception_handlers: dict[typing.Any, typing.Callable[[Request, Exception], Response]] = {}
    • self.debug 是一个布尔值,表示是否开启调试模式。
    • error_handler 用于存储处理 500 错误或通用异常的处理器。
    • exception_handlers 是一个字典,用于存储特定异常类型的处理器。
  2. 遍历异常处理器:

    python 复制代码
    for key, value in self.exception_handlers.items():
        if key in (500, Exception):
            error_handler = value
        else:
            exception_handlers[key] = value
    • 遍历 self.exception_handlers 字典中的每个键值对。
    • 如果键是 500 或 Exception,则将对应的值赋给 error_handler。
    • 否则,将键值对添加到 exception_handlers 字典中。
  3. 构建中间件列表:

    python 复制代码
    middleware = (
        [Middleware(ServerErrorMiddleware, handler=error_handler, debug=debug)]
        + self.user_middleware
        + [Middleware(ExceptionMiddleware, handlers=exception_handlers, debug=debug)]
    )
    • 创建一个中间件列表 middleware。
    • 首先添加一个 ServerErrorMiddleware 实例,用于处理服务器错误,传递 error_handler 和 debug 参数。
    • 然后添加用户自定义的中间件 self.user_middleware。
    • 最后添加一个 ExceptionMiddleware 实例,用于处理其他异常,传递 exception_handlers 和 debug 参数。
  4. 构建中间件栈:

    python 复制代码
    app = self.router
    for cls, args, kwargs in reversed(middleware):
        app = cls(app=app, *args, **kwargs)
    • 初始化 app 为 self.router,这是应用的路由处理程序。
    • 反向遍历 middleware 列表,确保中间件按照正确的顺序被应用。
    • 对于每个中间件类 cls,使用 app 作为参数创建一个新的中间件实例,并将结果赋值回 app。
  5. 返回最终的应用:

    python 复制代码
    return app
    • 返回最终构建好的 ASGI 应用 app。

总结

这个函数的主要作用是构建一个中间件栈,其中包含处理服务器错误和特定异常的中间件,以及用户自定义的中间件。通过反向遍历中间件列表,确保中间件按照正确的顺序被应用到应用的路由处理程序上。最终返回一个完整的 ASGI 应用。

执行顺序

  1. Middleware:

    • Middleware 是在请求到达路由处理函数之前和响应返回客户端之后执行的。
    • Middleware 按照它们在应用中注册的顺序从上到下依次执行。
    • 在请求阶段,Middleware 会按顺序依次执行。
    • 在响应阶段,Middleware 会按逆序执行(即最后一个注册的 Middleware 最先执行)。
  2. Exception Handler:

    • Exception Handler 是在处理请求过程中抛出异常时执行的。
    • 如果在 Middleware 或路由处理函数中抛出了异常,并且该异常没有被其他代码捕获,那么 FastAPI 会查找注册的异常处理器来处理这个异常。
    • Exception Handler 的执行优先级高于 Middleware 的响应处理部分。

具体流程

  1. 请求阶段:

    • 请求首先经过 Middleware。
    • 然后请求被传递给路由处理函数。
    • 如果在 Middleware 或路由处理函数中抛出了异常,FastAPI 会查找并调用相应的 Exception Handler。
  2. 响应阶段:

    • 路由处理函数生成响应。
    • 响应经过 Exception Handler(如果有的话)。
    • 响应再经过 Middleware 的响应处理部分,按逆序执行。

示例

假设你有以下 FastAPI 应用:

python 复制代码
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.middleware import Middleware

app = FastAPI()

# Middleware 1
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response

# Middleware 2
@app.middleware("http")
async def add_custom_header(request: Request, call_next):
    response = await call_next(request)
    response.headers["X-Custom-Header"] = "CustomValue"
    return response

# Exception Handler
@app.exception_handler(ValueError)
async def value_error_exception_handler(request: Request, exc: ValueError):
    return JSONResponse(
        status_code=400,
        content={"message": str(exc)},
    )

# Route
@app.get("/")
async def read_root():
    raise ValueError("This is a value error")
    return {"Hello": "World"}

执行顺序分析

  1. 请求阶段:

    • 请求首先经过 add_custom_header Middleware。
    • 然后经过 add_process_time_header Middleware。
    • 最后到达路由处理函数 read_root。
  2. 异常处理:

    • 在 read_root 中抛出 ValueError。
    • FastAPI 查找并调用 value_error_exception_handler,生成一个 400 错误响应。
  3. 响应阶段:

    • 响应首先经过 add_process_time_header Middleware。
    • 然后经过 add_custom_header Middleware。
    • 最后返回给客户端。

通过以上分析,你可以看到 Middleware 和 Exception Handler 的执行顺序及其在请求和响应处理中的角色。希望这能帮助你更好地理解和使用 FastAPI。

相关推荐
Cosolar4 小时前
不收费、不加水印、数据归你:我做了个开源的在线简历工具
后端·面试·前端框架
小蒜学长5 小时前
基于Spring Boot+Vue3的在线医疗咨询系统的设计与实现(代码+数据库+LW)
java·spring boot·后端·在线问诊·在线医疗咨询系统
陈随易6 小时前
下载神器!Motrix 停更三年后重写回归
前端·后端·程序员
每天一道题6 小时前
CAP、Raft 与多数派:分布式系统如何达成一致?
分布式·后端·微服务
前端的日常6 小时前
一个人+AI做情侣食谱小程序,0 费用的服务器
前端·后端
IT_陈寒7 小时前
Vue的v-for里用了个临时变量,页面直接挂了
前端·人工智能·后端
ServBay7 小时前
本地模型已经跑起来了,Copilot Fusion 为什么还要联网?
后端·ai编程·github copilot
武子康8 小时前
H3-World 的动作没按时发生,先检查时间线变成了什么
人工智能·后端·agent
苍何8 小时前
腾讯 Buddy One 来了,办公全家桶一键打通WorkBuddy(附教程)
后端
GIS数据转换器9 小时前
基于CIM的城市智慧供热监管服务平台
java·大数据·开发语言·人工智能·后端·物联网·struts