首页
/ FastAPI 进阶中间件:使用 add_middleware 集成 ASGI 中间件与 HTTPS 重定向、可信主机、GZip 压缩

FastAPI 进阶中间件:使用 add_middleware 集成 ASGI 中间件与 HTTPS 重定向、可信主机、GZip 压缩

2026-09-05 20:12:53作者:温艾琴Wonderful

在 FastAPI 应用中,中间件(Middleware)是拦截并处理每个请求/响应的通用处理层。本文围绕 FastAPI 官方进阶中间件文档展开,讲解如何向 FastAPI 应用添加任意符合 ASGI 规范的第三方中间件,并逐一介绍 fastapi.middleware 中内置的三类常用中间件——HTTPSRedirectMiddlewareTrustedHostMiddlewareGZipMiddleware——的使用方法、可配置参数与默认值,并结合仓库源码说明这些内置中间件与 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.pyCORSMiddleware,见前述 CORS 章节)和 wsgi.py(用于在 ASGI 应用中挂载 WSGI 应用的 WSGIMiddleware)。

下面介绍最常用的三个内置中间件,示例代码均来自仓库 docs_src/advanced_middleware/ 目录。

HTTPSRedirectMiddleware:强制 HTTPS/WSS 重定向

作用:强制所有入站 请求 必须使用 httpswss 协议。任何以 httpws 协议访问的入站请求,都会被重定向到对应的安全协议地址。

完整示例(对应 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.comwww.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 压缩级别,取值为 19 的整数。数值越低压缩越快但输出文件更大;数值越高压缩越慢但输出文件更小 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)。

小结:中间件接入的通用模式

把本文的核心要点归纳为可复用的操作模式:

  1. 第三方中间件一律用 app.add_middleware(中间件类, **kwargs) 注册,而不是手动 新中间件(原应用) 包裹,以保证框架内部的错误处理与异常处理器中间件顺序正确;
  2. FastAPI 内置中间件是 Starlette 的便捷再导出(见 fastapi/middleware/),理解它们的 Starlette 来源有助于查阅更详尽的参数文档;
  3. 三类高频内置中间件各有分工HTTPSRedirectMiddleware 管协议安全(无需参数),TrustedHostMiddlewareHost 头校验与 www 收口(需 allowed_hosts,可选 www_redirect),GZipMiddleware 管响应压缩(minimum_sizecompresslevel 可按延迟/体积权衡调优);
  4. 所有中间件参数通过 add_middleware 的关键字参数传递,默认值以 Starlette 文档为准(GZipMiddleware 默认 minimum_size=500compresslevel=9)。

按以上模式,你可以在不影响端点代码的前提下,把任意 ASGI 中间件(安全、压缩、代理头等)叠加到 FastAPI 应用中,组成适合生产部署的中间件栈。

登录后查看全文
热门项目推荐
相关项目推荐