FastAPI中exception_handler和middleware 的执行顺序

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

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 字典中的每个键值对。
    • 如果键是 500Exception,则将对应的值赋给 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_handlerdebug 参数。
    • 然后添加用户自定义的中间件 self.user_middleware
    • 最后添加一个 ExceptionMiddleware 实例,用于处理其他异常,传递 exception_handlersdebug 参数。
  4. 构建中间件栈

    python 复制代码
    app = self.router
    for cls, args, kwargs in reversed(middleware):
        app = cls(app=app, *args, **kwargs)
    • 初始化 appself.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。

相关推荐
漂流瓶66666620 分钟前
Scala的模式匹配变量类型
开发语言·后端·scala
夏天吃哈密瓜25 分钟前
Scala中的正则表达式01
大数据·开发语言·后端·正则表达式·scala
( •̀∀•́ )9204 小时前
Spring Boot 启动流程详解
java·spring boot·后端
明明跟你说过5 小时前
Go 语言函数编程指南:定义、调用技巧与返回值机制
开发语言·后端·golang·go·go1.19
运维&陈同学5 小时前
【Dubbo03】消息队列与微服务之dubbo-admin 二进制与编译安装
linux·运维·服务器·后端·微服务·云原生·架构·dubbo
努力的小雨5 小时前
金仓数据库数据迁移实战:从MySQL到KES的顺利迁移
后端
brzhang7 小时前
解锁新姿势:10 倍效率刷 leetcode
前端·后端
小奏技术7 小时前
kafka如何获取topic一天的消息量
后端·消息队列
2401_857622667 小时前
SpringBoot 架构助力夕阳红公寓管理系统可持续发展战略
spring boot·后端·架构
_.Switch8 小时前
Python Web 开发 FastAPI 入门:从基础架构到框架比较
开发语言·前端·数据库·python·django·sqlite·fastapi