FastAPI 进阶中间件:使用 add_middleware 集成 ASGI 中间件与 HTTPS 重定向、可信主机、GZip 压缩
在 FastAPI 应用中,中间件(Middleware)是拦截并处理每个请求/响应的通用处理层。本文围绕 FastAPI 官方进阶中间件文档展开,讲解如何向 FastAPI 应用添加任意符合 ASGI 规范的第三方中间件,并逐一介绍 fastapi.middleware 中内置的三类常用中间件——HTTPSRedirectMiddleware、TrustedHostMiddleware 与 GZipMiddleware——的使用方法、可配置参数与默认值,并结合仓库源码说明这些内置中间件与 Starlette 的关系,帮助你在生产环境中为应用加上安全重定向、主机头校验与响应压缩等能力。
前置知识:基础中间件与 CORS
在进入进阶内容之前,建议先了解两个前置主题:
- 如何为应用添加自定义中间件(参见仓库中 自定义中间件文档,其对应的示例代码位于
docs_src/middleware/tutorial001_py310.py); - 如何使用
CORSMiddleware处理跨域资源共享(CORS)(参见 CORS 文档,对应示例位于docs_src/cors/tutorial001_py310.py)。
本文则聚焦于“如何引入其他(尤其是第三方)中间件,以及 FastAPI 内置的几类开箱即用的中间件”。
添加 ASGI 中间件
由于 FastAPI 基于 Starlette 构建,并实现了 ASGI 规范,因此任何符合 ASGI 规范的中间件都可以直接使用——它不需要专门为 FastAPI 或 Starlette 编写,只要遵循 ASGI 协议即可。
从源码结构看,ASGI 中间件普遍是“以 ASGI 应用作为第一个参数”的类。第三方 ASGI 中间件的文档通常会给出这样的用法:
from unicorn import UnicornMiddleware
app = SomeASGIApp()
new_app = UnicornMiddleware(app, some_config="rainbow")
即:用一个新的中间件类把原应用“包”起来,得到一个新的应用对象。这种写法在纯 ASGI 世界里是标准做法,但在 FastAPI 中并不推荐,因为它会改变中间件与框架内部机制的协作顺序。
FastAPI(实际上是 Starlette)提供了一种更简单、更安全的注册方式:app.add_middleware()。这样能保证框架内部用于处理服务器错误(Server Error)和自定义异常处理器(Exception Handlers)的中间件顺序正确、行为正常——如果在 add_middleware 之外手动包裹应用,这些内部机制可能被跳过或顺序错乱。
正确的注册方式是:
from fastapi import FastAPI
from unicorn import UnicornMiddleware
app = FastAPI()
app.add_middleware(UnicornMiddleware, some_config="rainbow")
app.add_middleware() 的签名约定是:第一个参数是中间件类本身(不是实例),其后所有关键字参数都会原样传递给该中间件的构造函数。上例中 some_config="rainbow" 会被传给 UnicornMiddleware 的构造函数,app 本身由框架在组装应用时自动注入。
这个模式在所有内置中间件中都一致,下面逐一演示。
内置中间件总览
FastAPI 自带若干面向常见应用场景的中间件,位于 fastapi/middleware/ 包中,开发者可以直接使用。
/// 技术细节:它们来自哪里?
你可能会看到这样的导入方式:from starlette.middleware.something import SomethingMiddleware。FastAPI 提供的这些中间件是通过 fastapi.middleware 暴露出来的“便捷入口”,目的是简化你的导入路径。
从源码可以直接验证这一点:fastapi/middleware/ 包中的模块都是对 Starlette 的再导出。例如 GZip 中间件:
from starlette.middleware.gzip import GZipMiddleware as GZipMiddleware # noqa
HTTPS 重定向中间件 与 可信主机中间件 同样是 from starlette.middleware... import ... as ... 的单行再导出;包入口 则再导出 Starlette 的 Middleware 类。因此:
- 绝大多数可用中间件直接来自 Starlette,其完整列表以 Starlette 官方文档为准;
- 使用
from fastapi.middleware.xxx import XxxMiddleware与使用from starlette.middleware.xxx import XxxMiddleware功能等价,选择前者只是更贴合 FastAPI 的项目习惯。
fastapi/middleware/ 目录中还包含 FastAPI 自身实现的 asyncexitstack.py(依赖清理的异步上下文工具)、cors.py(CORSMiddleware,见前述 CORS 章节)和 wsgi.py(用于在 ASGI 应用中挂载 WSGI 应用的 WSGIMiddleware)。
下面介绍最常用的三个内置中间件,示例代码均来自仓库 docs_src/advanced_middleware/ 目录。
HTTPSRedirectMiddleware:强制 HTTPS/WSS 重定向
作用:强制所有入站 请求 必须使用 https 或 wss 协议。任何以 http 或 ws 协议访问的入站请求,都会被重定向到对应的安全协议地址。
完整示例(对应 tutorial001_py310.py):
from fastapi import FastAPI
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
app = FastAPI()
app.add_middleware(HTTPSRedirectMiddleware)
@app.get("/")
async def main():
return {"message": "Hello World"}
要点说明:
HTTPSRedirectMiddleware无需任何配置参数,直接通过app.add_middleware(HTTPSRedirectMiddleware)注册即可;- 该中间件适合部署在负载均衡器/反向代理已终结 TLS、或应用直接暴露 HTTP 端口的场景,用于把不安全的
http://与ws://连接统一跳转到https://与wss://; - 它不参与业务逻辑,只负责协议层面的 307 类重定向,因此对端点代码无侵入。
TrustedHostMiddleware:防御 HTTP Host 头攻击
作用:强制所有入站请求必须携带合法设置的 Host 请求头,用于防范 HTTP Host 头攻击(攻击者伪造 Host 头,使应用生成指向恶意域名的链接,常用于密码重置链接劫持、缓存投毒等)。
完整示例(对应 tutorial002_py310.py):
from fastapi import FastAPI
from fastapi.middleware.trustedhost import TrustedHostMiddleware
app = FastAPI()
app.add_middleware(
TrustedHostMiddleware, allowed_hosts=["example.com", "*.example.com"]
)
@app.get("/")
async def main():
return {"message": "Hello World"}
支持的参数如下:
| 参数 | 说明 | 默认值 |
|---|---|---|
allowed_hosts |
允许作为 Host 的域名列表。支持 *.example.com 这类通配符域名以匹配子域名。如果要允许任意主机名,可设置 allowed_hosts=["*"]——但更建议直接不启用这个中间件 |
必选(需明确传入) |
www_redirect |
设为 True 时,对非 www 版本的合法主机的请求,会重定向到其对应的 www 版本 |
True |
行为细节:
- 当一个入站请求的
Host头未通过校验(不在允许列表内、通配符不匹配等),应用会返回400响应,而不是处理该请求; - 结合
www_redirect的行为,如果你的业务同时存在example.com与www.example.com,可以借助该参数统一收口到 www 域名,避免重复内容与 SEO 分裂。
GZipMiddleware:响应内容 GZip 压缩
作用:对 Accept-Encoding 请求头中包含 "gzip" 的请求,处理(压缩)GZip 响应。该中间件同时支持普通响应与流式响应(Streaming Responses),因此对流式端点(如 SSE、大文件分块传输)同样有效。
完整示例(对应 tutorial003_py310.py):
from fastapi import FastAPI
from fastapi.middleware.gzip import GZipMiddleware
app = FastAPI()
app.add_middleware(GZipMiddleware, minimum_size=1000, compresslevel=5)
@app.get("/")
async def main():
return "somebigcontent"
支持的参数如下:
| 参数 | 说明 | 默认值 |
|---|---|---|
minimum_size |
只有响应体大小大于等于该最小字节数时才会进行 GZip 压缩;更小的响应原样返回(压缩小响应收益极低,反而增加 CPU 开销) | 500(字节) |
compresslevel |
GZip 压缩级别,取值为 1 到 9 的整数。数值越低压缩越快但输出文件更大;数值越高压缩越慢但输出文件更小 |
9 |
选型建议:
- 默认参数
minimum_size=500, compresslevel=9偏向“尽可能压缩”;如果对延迟敏感、且响应多为 JSON API(压缩率有限),可以适当调低compresslevel(如示例中的5)以提升吞吐; - 如果响应多为纯文本/大 JSON,可以调低
minimum_size让更多响应参与压缩; - 由于它兼容流式响应,配合 FastAPI 的流式返回(
StreamingResponse等)时,压缩仍然生效,无需额外处理。
其他可用的 ASGI 中间件
除上述内置中间件外,生态中还有大量现成的 ASGI 中间件,都可以按 app.add_middleware() 的同一模式接入,例如:
- Uvicorn 的
ProxyHeadersMiddleware:用于处理反向代理(如 Nginx)传来的代理头,正确还原真实客户端 IP 与协议。如果你的 FastAPI 应用部署在代理之后,这是必须了解的中间件(仓库中 behind-a-proxy 文档 专门讲解该场景); - MessagePack ASGI 中间件:为 ASGI 应用增加 MessagePack 编解码支持。
更多可用中间件请参考 Starlette 官方中间件文档与社区维护的 ASGI 资源列表(Awesome-ASGI)。
小结:中间件接入的通用模式
把本文的核心要点归纳为可复用的操作模式:
- 第三方中间件一律用
app.add_middleware(中间件类, **kwargs)注册,而不是手动新中间件(原应用)包裹,以保证框架内部的错误处理与异常处理器中间件顺序正确; - FastAPI 内置中间件是 Starlette 的便捷再导出(见 fastapi/middleware/),理解它们的 Starlette 来源有助于查阅更详尽的参数文档;
- 三类高频内置中间件各有分工:
HTTPSRedirectMiddleware管协议安全(无需参数),TrustedHostMiddleware管Host头校验与 www 收口(需allowed_hosts,可选www_redirect),GZipMiddleware管响应压缩(minimum_size、compresslevel可按延迟/体积权衡调优); - 所有中间件参数通过
add_middleware的关键字参数传递,默认值以 Starlette 文档为准(GZipMiddleware默认minimum_size=500、compresslevel=9)。
按以上模式,你可以在不影响端点代码的前提下,把任意 ASGI 中间件(安全、压缩、代理头等)叠加到 FastAPI 应用中,组成适合生产部署的中间件栈。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00