FastAPI 中间件使用:CORS 与 GZip 压缩

发布于:2025-02-11 ⋅ 阅读:(228) ⋅ 点赞:(0)

FastAPI 中间件详解:CORS 与 GZip 压缩

在 FastAPI 中,中间件(Middleware)是一种强大的工具,用于在请求和响应之间执行全局性任务。本文将深入探讨两个常用的中间件:CORSMiddleware 和 CustomGZipMiddleware,并通过丰富的示例和知识点,帮助你全面掌握它们的使用场景和实现原理。


1. 什么是中间件?

中间件是一种在请求到达应用程序之前或响应返回客户端之前执行的代码。它可以用于处理跨域请求、压缩响应、认证、日志记录等任务。FastAPI 提供了灵活的中间件机制,允许开发者轻松扩展应用的功能。

中间件的工作原理

  1. 请求阶段:中间件在请求到达路由处理函数之前执行,可以修改请求或执行某些操作(如认证检查)。
  2. 响应阶段:中间件在路由处理函数返回响应之后执行,可以修改响应或执行某些操作(如压缩响应)。

2. CORS 中间件:解决跨域问题

什么是 CORS?

跨域资源共享(CORS)是一种机制,允许浏览器向不同域名的服务器发起请求。如果没有正确配置 CORS,浏览器会阻止跨域请求,导致前端应用无法访问后端 API。

使用 CORSMiddleware

FastAPI 提供了 CORSMiddleware,用于处理跨域请求。以下是一个完整的配置示例:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# 添加 CORS 中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],  # 允许的前端域名
    allow_credentials=True,  # 允许携带凭证(如 cookies)
    allow_methods=["GET", "POST", "PUT", "DELETE"],  # 允许的 HTTP 方法
    allow_headers=["*"],  # 允许的 HTTP 头
)
参数详解
  • allow_origins:允许跨域请求的源(域名)。可以指定多个域名,或使用 ["*"] 允许所有域名。
  • allow_credentials:是否允许携带凭证(如 cookies)。
  • allow_methods:允许的 HTTP 方法,如 ["GET", "POST"]。
  • allow_headers:允许的 HTTP 头,如 ["Authorization", "Content-Type"]。
示例场景

假设你的前端应用运行在 http://localhost:3000,后端 API 运行在 http://localhost:8000。通过配置 CORSMiddleware,前端可以成功访问后端 API。


3. GZip 压缩中间件:优化响应性能

什么是 GZip 压缩?

GZip 是一种常用的数据压缩算法,用于减少 HTTP 响应的大小,从而提高网络传输效率。FastAPI 提供了 GZipMiddleware,支持对响应进行自动压缩。

自定义 CustomGZipMiddleware

在某些场景下,你可能希望排除某些路径的响应压缩。以下是一个自定义的 GZip 中间件实现:

from fastapi import FastAPI, Request
from starlette.middleware.gzip import GZipMiddleware, GZipResponder
from starlette.datastructures import Headers
from starlette.types import ASGIApp, Receive, Scope, Send

class CustomGZipMiddleware(GZipMiddleware):
    def __init__(
        self, app: ASGIApp, minimum_size: int = 500, compresslevel: int = 9, exclude_paths=None
    ) -> None:
        super().__init__(app, minimum_size, compresslevel)
        self.exclude_paths = exclude_paths or []

    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        if scope["type"] == "http":
            headers = Headers(scope=scope)
            request = Request(scope, receive)
            if "gzip" in headers.get("Accept-Encoding", "") and not any(request.url.path.endswith(suffix) for suffix in self.exclude_paths):
                responder = GZipResponder(
                    self.app, self.minimum_size, compresslevel=self.compresslevel
                )
                await responder(scope, receive, send)
                return
        await self.app(scope, receive, send)

def add_gzip_middleware(app: FastAPI):
    """
    添加 GZip 压缩中间件
    """
    exclude_paths = ['/ai_communication/AiCommunicationThemesRecord/chat']
    app.add_middleware(CustomGZipMiddleware, minimum_size=1000, compresslevel=9, exclude_paths=exclude_paths)
参数详解
  • minimum_size:只有响应体大小超过这个值(字节)时,才会进行压缩。
  • compresslevel:压缩级别,范围是 1 到 9,9 表示最高压缩率。
  • exclude_paths:排除某些路径,不对这些路径的响应进行压缩。
示例场景

假设你有一个路径 /ai_communication/AiCommunicationThemesRecord/chat,你希望该路径的响应不被压缩。通过配置 CustomGZipMiddleware,可以实现这一需求。


4. 综合示例

以下是一个完整的 FastAPI 应用示例,同时使用了 CORSMiddleware 和 CustomGZipMiddleware:

from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.gzip import GZipMiddleware, GZipResponder
from starlette.datastructures import Headers
from starlette.types import ASGIApp, Receive, Scope, Send

app = FastAPI()

# 添加 CORS 中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["*"],
)

# 自定义 GZip 中间件
class CustomGZipMiddleware(GZipMiddleware):
    def __init__(
        self, app: ASGIApp, minimum_size: int = 500, compresslevel: int = 9, exclude_paths=None
    ) -> None:
        super().__init__(app, minimum_size, compresslevel)
        self.exclude_paths = exclude_paths or []

    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        if scope["type"] == "http":
            headers = Headers(scope=scope)
            request = Request(scope, receive)
            if "gzip" in headers.get("Accept-Encoding", "") and not any(request.url.path.endswith(suffix) for suffix in self.exclude_paths):
                responder = GZipResponder(
                    self.app, self.minimum_size, compresslevel=self.compresslevel
                )
                await responder(scope, receive, send)
                return
        await self.app(scope, receive, send)

# 添加 GZip 中间件
exclude_paths = ['/ai_communication/AiCommunicationThemesRecord/chat']
app.add_middleware(CustomGZipMiddleware, minimum_size=1000, compresslevel=9, exclude_paths=exclude_paths)

# 示例路由
@app.get("/")
def read_root():
    return {"message": "Hello, World!"}

@app.get("/ai_communication/AiCommunicationThemesRecord/chat")
def chat():
    return {"message": "This response is not compressed."}

5. 总结

通过本文的学习,你应该已经掌握了以下内容:

  1. 中间件的作用:在请求和响应之间执行全局性任务。
  2. CORSMiddleware:解决跨域问题,允许前端应用访问后端 API。
  3. CustomGZipMiddleware:压缩响应,优化网络传输性能,并支持排除特定路径。

在实际开发中,合理使用中间件可以显著提升应用的性能和安全性。希望本文能帮助你更好地理解和使用 FastAPI 中间件!



微信公众号

今日签到

点亮在社区的每一天
去签到