恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
FastAPI 中间件(Middleware)完全指南:请求拦截、响应处理与执行顺序深度解析
首页
资讯中心
/
FastAPI 中间件(Middleware)完全指南:请求拦截、响应处理与执行顺序深度解析
FastAPI 中间件(Middleware)完全指南:请求拦截、响应处理与执行顺序深度解析
发布时间:2026/9/8 18:12:19
FastAPI 中间件Middleware完全指南请求拦截、响应处理与执行顺序深度解析【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi本文基于 FastAPI 官方教程文档docs/hi/docs/tutorial/middleware.md与英文版 docs/en/docs/tutorial/middleware.md 同源整理。核心主题是在FastAPIapplication 中添加自定义 HTTP 中间件拦截进入应用的每一个请求、在交给具体path operation之前做处理并在响应返回客户端之前做二次加工。读完本文你将掌握app.middleware(http)装饰器的完整用法、如何在响应中注入自定义 Header、yield依赖与 Background Tasks 的执行时序以及多个中间件的栈式执行顺序并了解其底层在 Starlette 基础之上是如何实现的。什么是中间件在 FastAPI 中中间件middleware是一个函数它会与**每一个请求request打交道——在请求被任何一个具体的path operation处理之前同时也会与每一个响应response**打交道——在响应被返回给客户端之前。一个中间件的完整工作流程包含以下 6 个步骤它接住发往你 application 的每一个请求它可以对该request做一些处理或执行任何需要的代码然后它把request交给 application 的其余部分去处理由某个path operation完成它随后拿到由 application即某个path operation生成的response它可以对该response做一些处理或执行任何需要的代码最后它把response返回出去。换句话说中间件就像包在路由处理逻辑外面的一层洋葱皮请求进来先经过它响应出去也先经过它。与yield依赖、后台任务的技术时序官方文档在技术细节Technical Details中特别澄清了两个容易混淆的执行时序问题如果你使用带yield的依赖那么该依赖的exit codeyield之后的收尾代码会在中间件之后执行如果存在后台任务background tasks见 Background Tasks 一节那么它们会在所有中间件都执行完之后才运行。也就是说从响应生命周期看顺序大致是path operation→ 带yield依赖的退出代码 → 中间件 → 后台任务。理解这一点有助于避免在中间件里提前做那些本该由依赖清理或后台任务完成的工作。创建第一个中间件app.middleware(http)创建自定义 HTTP 中间件最简单的方式是在一个函数上方使用装饰器app.middleware(http)。这个中间件函数会收到两个关键对象request当前进入的请求call_next一个接收request作为参数的函数——它会把request传递给对应的path operation然后返回该 *path operation 生成的response。拿到call_next(request)返回的response之后你可以在最终返回它之前对它做任意修改。下面是一份完整、可直接运行的示例来自 docs_src/middleware/tutorial001_py310.py需 Python 3.10import time from fastapi import FastAPI, Request app FastAPI() app.middleware(http) async def add_process_time_header(request: Request, call_next): start_time time.perf_counter() response await call_next(request) process_time time.perf_counter() - start_time response.headers[X-Process-Time] str(process_time) return responseRequest从哪来注意上例中的request: Request其类型来自fastapi.Request。官方技术细节指出你也可以直接写from starlette.requests import Request。FastAPI之所以提供fastapi.Request纯粹是出于开发者便利它本质上直接来自 Starlette。同理call_next也是一个典型的 StarletteBaseHTTPMiddlewaredispatch 接口。源码中的落地方式它其实是add_middleware(BaseHTTPMiddleware, ...)查看 applications.py 中FastAPI.middleware()的实现约第 4683 行起可以看到装饰器的本质def middleware( self, middleware_type: Annotated[str, Doc(The type of middleware. Currently only supports http.)], ) - Callable[[DecoratedCallable], DecoratedCallable]: def decorator(func: DecoratedCallable) - DecoratedCallable: self.add_middleware(BaseHTTPMiddleware, dispatchfunc) return func return decorator也就是说app.middleware(http)会把你写的函数作为dispatch参数注册为一个 Starlette 的BaseHTTPMiddleware。当前类型参数仅支持字符串http。这解释了为什么中间件函数必须写成async def、为什么签名固定为(request, call_next)——它们完全对应BaseHTTPMiddleware.dispatch的约定。call_next之前与之后请求/响应两侧的代码利用中间件函数天然的分段结构你可以同时在请求侧和响应侧挂代码call_next(request)之前的代码在path operation收到请求前运行call_next(request)之后、return response之前的代码在响应已生成但尚未返回给客户端时运行。上面示例正是这一模式的典型应用用time.perf_counter()记录请求开始时间await call_next(request)拿到响应后立即再次计时求差并把耗时秒写入自定义响应头X-Process-Time。为什么用time.perf_counter()而不是time.time()官方建议在此类性能计时场景使用 Python 标准库的time.perf_counter()因为它提供更高精度的单调时钟适合测量极短的代码执行间隔不受系统时钟调整的影响。time.time()更适合表示墙上时钟wall-clock时间不适合做高精度差分计时。自定义 Header 与 CORS 的联动注意事项中间件里设置的自定义专有 Headercustom proprietary headers可以遵循惯例加上X-前缀例如上例的X-Process-Time。但有一个非常实际的坑如果你希望浏览器中的客户端前端 JS能够读到这些自定义响应头仅仅在中间件里设置是不够的——你还必须在 CORS 配置中通过expose_headers参数把它们显式暴露出去。相关配置见 CORS跨域资源共享 一节以及在 docs/en/docs/advanced/middleware.md 中引用的 Starlette CORS 文档说明。换句话说中间件负责写入自定义响应头CORS 的expose_headers负责让浏览器允许读取两者缺一不可。多个中间件的执行顺序栈式叠加当你通过app.middleware()装饰器或app.add_middleware()方法添加多个中间件时每一个新中间件都会把 application 再包一层从而形成一个栈stack最后添加的中间件位于最外层outermost最先添加的中间件位于最内层innermost。执行规则非常明确在请求路径request path上最外层的中间件最先运行在响应路径response path上最外层的中间件最后运行。官方文档给出了直观示例app.add_middleware(MiddlewareA) app.add_middleware(MiddlewareB)得到的执行顺序是请求方向MiddlewareB → MiddlewareA → route响应方向route → MiddlewareA → MiddlewareB这种 stacking 行为保证了中间件总在一个可预测、可控的顺序中执行——这正是洋葱模型的典型体现。源码层面的顺序佐证在 applications.py 的build_middleware_stack()方法约第 1020 行起中可以看到FastAPI 会这样组装整个中间件链middleware ( [Middleware(ServerErrorMiddleware, handlererror_handler, debugdebug)] self.user_middleware [ Middleware(ExceptionMiddleware, handlersexception_handlers, debugdebug), # FastAPI-specific AsyncExitStackMiddleware ... ] )其中self.user_middleware正是通过add_middleware/app.middleware收集到的、按注册先后顺序排列的用户中间件列表定义见该文件约第 1014 行self.user_middleware [] if middleware is None else list(middleware)。Starlette 的build_middleware_stack会从列表尾部开始逐层 wrap从而实现了后注册者在外层、先注册者在内层的栈式效果。此外FastAPI 特意在ExceptionMiddleware之后、用户中间件之内插入AsyncExitStackMiddleware以保证流式响应和文件关闭等清理逻辑能正常工作——这属于框架内部实现细节但解释了为什么官方推荐始终通过app.add_middleware()添加中间件而不是手工把 app 包一层那样会破坏异常处理器与内部中间件的协同。用测试验证中间件行为仓库自带的测试用例tests/test_tutorial/test_middleware/test_tutorial001.py验证了上述示例的行为from fastapi.testclient import TestClient from docs_src.middleware.tutorial001_py310 import app client TestClient(app) def test_response_headers(): response client.get(/openapi.json) assert response.status_code 200, response.text assert X-Process-Time in response.headers它通过TestClient发起一次/openapi.json请求断言响应头中确实包含X-Process-Time。这从测试角度证明了中间件会作用于每一个经过 application 的请求——即使该请求最终落到的是 FastAPI 内置的 OpenAPI schema 路由而非开发者自定义的path operation。如果你想亲自运行这段示例可把上面示例保存为本地文件并启动服务然后对任意路径例如/openapi.json发起请求用浏览器开发者工具或curl -i观察响应头中新增的X-Process-Time。需要注意运行前提示例使用 Python 3.10 语法且本地需已安装 fastapi 与任一 ASGI 服务器如 uvicorn。更多的内置与第三方中间件本文介绍的是自定义HTTP 中间件的写法与执行模型。FastAPI 自身还捆绑了一批开箱即用的中间件位于 fastapi/middleware 目录下例如CORSMiddleware跨域处理见 CORSHTTPSRedirectMiddleware强制 HTTP/WS 跳转到 HTTPS/WSSTrustedHostMiddleware校验Host请求头防御 HTTP Host Header 攻击支持allowed_hosts、www_redirect参数校验失败返回400GZipMiddleware对Accept-Encoding含gzip的请求做 GZip 压缩响应支持minimum_size默认 500 字节与compresslevel1–9默认 9参数WSGIMiddleware、AsyncExitStackMiddleware等。这些中间件大多在fastapi/middleware中做了再导出re-export例如 fastapi/middleware/cors.py 里的from starlette.middleware.cors import CORSMiddleware因此你可以直接from fastapi.middleware.cors import CORSMiddleware。由于 FastAPI 基于 Starlette 并完整实现 ASGI 规范任何遵循 ASGI 规范的第三方中间件都可以通过app.add_middleware(SomeMiddleware, some_config...)的方式接入——add_middleware的第一个参数是中间件类后续参数会传给该类的构造器。官方建议始终使用app.add_middleware()而非手动SomeMiddleware(app)包裹因为前者能确保服务器错误处理和自定义异常处理器正常工作。更多中间件的逐一讲解与参数细节可继续阅读同一仓库中的进阶文档 Advanced User Guide: Advanced Middleware英文版见 docs/en/docs/advanced/middleware.md而紧随本教程之后的下一节则是用CORSMiddleware处理跨域问题的完整实战。【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考