Fastapi 进阶二:Fastapi中间件

FastAPI 中间件概述

在 FastAPI 框架中,中间件(Middleware)是一种用于在请求到达路由处理函数之前或响应返回客户端之前进行额外处理的机制。中间件可以用于执行各种任务,例如身份验证、日志记录、请求修改、跨域资源共享(CORS)控制等。通过中间件,开发者可以在不修改业务逻辑代码的情况下,增强或改变请求和响应的处理流程。FastAPI 提供了多种内置中间件,并支持自定义中间件的开发,使得开发者能够灵活地扩展应用的功能。

中间件在 FastAPI 中扮演着至关重要的角色。它允许开发者在请求处理的各个阶段插入自定义逻辑,从而实现统一的请求处理策略。例如,CORS 中间件可以用于解决浏览器跨域请求的问题,HTTPSRedirectMiddleware 可以强制将 HTTP 请求重定向到 HTTPS,而 TrustedHostMiddleware 则可以防止恶意的主机头攻击。此外,开发者还可以基于 BaseHTTPMiddleware 自定义中间件,以满足特定的需求,如记录请求日志、添加链路追踪 ID 或实现 IP 白名单控制。

FastAPI 中间件的核心功能是处理请求和响应的中间层逻辑,为应用程序提供统一的处理方式。通过合理使用中间件,开发者可以提高代码的可维护性、增强系统的安全性,并优化请求处理流程。在接下来的内容中,我们将深入探讨 FastAPI 中间件的使用方式,包括内置中间件的配置、自定义中间件的实现,以及具体的应用场景。

使用 @app.middleware 装饰器创建中间件

在 FastAPI 中,
@app.middleware
装饰器提供了一种便捷的方式来定义自定义中间件。通过该装饰器,开发者可以编写一个异步函数,并将其注册为中间件,从而在请求处理过程中执行自定义逻辑。FastAPI 的中间件本质上是一个异步函数,接收
request

call_next
作为参数,并返回一个
Response
对象。其中,
request
表示当前的请求对象,
call_next
是一个函数,用于将请求传递给下一个中间件或最终的路由处理函数。

使用
@app.middleware
装饰器创建中间件的基本语法如下:


from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

app = FastAPI()

@app.middleware("http")
async def custom_middleware(request: Request, call_next):
    # 在请求到达路由处理函数之前执行的逻辑
    print("Before request processing")
    
    response = await call_next(request)  # 将请求传递给下一个中间件或路由处理函数
    
    # 在响应返回客户端之前执行的逻辑
    print("After response generation")
    
    return response

在上述示例中,
@app.middleware("http")
表示该中间件仅应用于 HTTP 请求。中间件函数接收
request

call_next
两个参数,并在处理完请求后调用
call_next(request)
来继续请求的处理流程。开发者可以在
call_next
之前或之后添加自定义逻辑,例如记录请求信息、修改请求头或处理响应内容。

通过
@app.middleware
装饰器,开发者可以轻松地在 FastAPI 应用中插入自定义中间件,以满足特定的业务需求。这种中间件机制使得请求处理流程更加灵活,同时保持代码的可维护性和可扩展性。在实际应用中,开发者可以利用这一机制实现诸如身份验证、日志记录或性能监控等功能。

使用 CORSMiddleware 解决跨域问题

在 Web 开发中,由于浏览器的同源策略(Same-Origin Policy),前端应用与后端 API 之间的跨域请求(Cross-Origin Request)可能会受到限制。当浏览器检测到请求的源(协议、域名、端口)与目标 API 不一致时,会阻止请求的执行。为了解决这一问题,FastAPI 提供了内置的
CORSMiddleware
,用于处理跨域请求,并通过配置允许特定的来源、方法和头信息,从而确保 API 可以被合法的前端应用访问。

在 FastAPI 应用中,可以通过
app.add_middleware
方法添加
CORSMiddleware
,并传入相关配置参数。以下是一个完整的代码示例,展示如何在 FastAPI 应用中配置
CORSMiddleware
以允许跨域请求:


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

app = FastAPI()

# 配置 CORSMiddleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 允许所有来源,也可以指定具体的域名
    allow_credentials=True,  # 是否允许跨域请求携带凭证(如 Cookie)
    allow_methods=["*"],  # 允许所有 HTTP 方法
    allow_headers=["*"],  # 允许所有请求头
)

@app.get("/")
def read_root():
    return {"message": "Hello, CORS is enabled!"}

在上述示例中,
allow_origins
参数用于指定允许跨域请求的来源,
"*"
表示允许所有来源。如果只需要允许特定的域名,则可以替换为具体的域名列表,如
["https://example.com", "https://sub.example.com"]

allow_credentials
参数用于控制是否允许跨域请求携带 Cookie 或其他凭证信息,
allow_methods

allow_headers
则分别用于指定允许的 HTTP 方法和请求头。

通过合理配置
CORSMiddleware
,开发者可以确保 FastAPI 应用能够正确处理跨域请求,从而满足现代 Web 应用的前后端分离架构需求。同时,配置合适的 CORS 策略也有助于增强 API 的安全性,避免不必要的跨域攻击风险。

CORSMiddleware 源码解析


CORSMiddleware
是 FastAPI 内置的中间件之一,用于处理跨域请求(Cross-Origin Requests)。其核心功能是在响应中添加适当的 CORS 相关头信息,以允许浏览器根据配置的策略决定是否允许跨域访问。通过分析
CORSMiddleware
的源码,我们可以深入了解其内部逻辑,包括如何处理 OPTIONS 请求、如何设置响应头,以及如何匹配允许的来源、方法和头信息。

在 FastAPI 的源码中,
CORSMiddleware
的实现位于
fastapi/middleware/cors.py
文件中。该中间件继承自
BaseHTTPMiddleware
,并实现了
dispatch
方法,用于处理请求和响应。以下是
CORSMiddleware
的关键逻辑:

处理 OPTIONS 请求
当浏览器发送预检请求(Preflight Request)时,即
OPTIONS
方法的请求,
CORSMiddleware
会直接处理该请求,而不会将其传递给后续的中间件或路由处理函数。预检请求的目的是让浏览器确认服务器是否允许跨域请求。
CORSMiddleware
会在响应中设置
Access-Control-Allow-Methods

Access-Control-Allow-Headers
等头信息,以告知浏览器服务器支持的跨域方法和头字段。

设置响应头
对于非预检请求,
CORSMiddleware
会在请求处理完成后,在响应中添加一系列 CORS 相关头信息,包括:


Access-Control-Allow-Origin
:指定允许访问的来源。
Access-Control-Allow-Credentials
:指示是否允许跨域请求携带凭证(如 Cookie)。
Access-Control-Expose-Headers
:指定允许暴露给前端的响应头。
Access-Control-Max-Age
:设置预检请求的有效期。
这些头信息的值由
CORSMiddleware
的配置参数决定,如
allow_origins

allow_credentials

allow_headers
等。

匹配允许的来源

CORSMiddleware
会检查当前请求的来源是否在
allow_origins
列表中。如果请求的来源被允许,则会在响应中添加相应的
Access-Control-Allow-Origin
头,否则不会添加该头,导致浏览器拒绝该请求。

处理请求方法和头字段

CORSMiddleware
会检查请求的 HTTP 方法和头字段是否在允许的范围内。如果请求的方法不在
allow_methods
列表中,或者头字段不在
allow_headers
列表中,则浏览器可能会拒绝该请求。

通过上述机制,
CORSMiddleware
能够有效地控制跨域请求的访问权限,确保 API 既能支持合法的跨域访问,又能防止潜在的安全风险。开发者可以通过合理配置
CORSMiddleware
的参数,以满足不同的业务需求。

其他常用中间件的使用

除了
CORSMiddleware
,FastAPI 还提供了多个内置中间件,用于处理常见的请求和安全问题。其中,
HTTPSRedirectMiddleware

TrustedHostMiddleware
是两个重要的中间件,分别用于强制 HTTPS 访问和防止恶意主机头攻击。

HTTPSRedirectMiddleware

在现代 Web 应用中,使用 HTTPS 协议是保障数据传输安全的重要手段。然而,在某些情况下,用户可能会通过 HTTP 访问 API,而未启用 HTTPS。为了确保所有请求都通过加密连接进行,FastAPI 提供了
HTTPSRedirectMiddleware
,它可以自动将 HTTP 请求重定向到 HTTPS,从而提升应用的安全性。

以下是如何在 FastAPI 应用中使用
HTTPSRedirectMiddleware
的示例:


from fastapi import FastAPI
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware

app = FastAPI()

# 添加 HTTPSRedirectMiddleware
app.add_middleware(HTTPSRedirectMiddleware)

@app.get("/")
def read_root():
    return {"message": "This request is enforced to use HTTPS."}

在上述代码中,当用户通过 HTTP 发起请求时,
HTTPSRedirectMiddleware
会自动将请求重定向到 HTTPS。例如,如果用户访问
http://example.com/api
,中间件会返回一个 307 临时重定向状态码,并将请求重定向到
https://example.com/api
。这种方式可以有效确保所有请求都通过加密通道进行,提高数据的安全性。

TrustedHostMiddleware


TrustedHostMiddleware
用于防止恶意的主机头攻击(Host Header Attack)。在某些情况下,攻击者可能会伪造请求的 Host 头,从而导致服务器处理错误的请求。
TrustedHostMiddleware
可以限制服务器只接受来自指定主机的请求,从而防止此类攻击。

以下是一个使用
TrustedHostMiddleware
的示例:


from fastapi import FastAPI
from fastapi.middleware.trustedhost import TrustedHostMiddleware

app = FastAPI()

# 添加 TrustedHostMiddleware,并指定允许的主机名
app.add_middleware(TrustedHostMiddleware, allowed_hosts=["example.com", "api.example.com"])

@app.get("/")
def read_root():
    return {"message": "Host header is verified by TrustedHostMiddleware."}

在上述代码中,
allowed_hosts
参数指定了允许的主机名。当请求的 Host 头不在该列表中时,
TrustedHostMiddleware
会拒绝请求,并返回 400 错误。这种方式可以有效防止非法的主机头攻击,增强 API 的安全性。

通过使用
HTTPSRedirectMiddleware

TrustedHostMiddleware
,开发者可以在 FastAPI 应用中增强安全性,确保请求通过加密连接进行,并防止恶意的主机头攻击。

基于 BaseHTTPMiddleware 实现自定义中间件

除了使用 FastAPI 内置的中间件,开发者还可以基于
BaseHTTPMiddleware
自定义中间件,以满足特定的业务需求。
BaseHTTPMiddleware
是 FastAPI 提供的一个基类,用于构建自定义中间件。通过继承该类并实现
dispatch
方法,开发者可以定义自定义的请求和响应处理逻辑。

以下是一个简单的自定义中间件示例,该中间件会在响应中添加一个自定义头字段
X-Custom-Header


from fastapi import FastAPI, Request
from fastapi.middleware.base import BaseHTTPMiddleware
from fastapi.responses import Response

app = FastAPI()

class CustomHeaderMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        # 在请求处理之前执行的逻辑
        print("Processing request...")

        # 调用下一个中间件或路由处理函数
        response = await call_next(request)

        # 在响应返回之前执行的逻辑
        response.headers["X-Custom-Header"] = "CustomValue"

        return response

# 将自定义中间件添加到 FastAPI 应用中
app.add_middleware(CustomHeaderMiddleware)

@app.get("/")
def read_root():
    return {"message": "Custom middleware is working!"}

在上述示例中,
CustomHeaderMiddleware
类继承自
BaseHTTPMiddleware
,并实现了
dispatch
方法。该方法接收
request

call_next
作为参数,其中
call_next
用于调用下一个中间件或路由处理函数。在示例中,
dispatch
方法首先打印一条日志,然后调用
call_next
以继续请求处理流程。在获取到响应后,中间件向响应头中添加了一个自定义字段
X-Custom-Header
,并返回修改后的响应。

通过这种方式,开发者可以灵活地扩展 FastAPI 的中间件功能,实现诸如日志记录、身份验证、链路追踪、IP 白名单等常见需求。自定义中间件的使用方式与内置中间件类似,只需将其注册到 FastAPI 应用即可。这种方式不仅提高了代码的可维护性,还增强了应用的可扩展性,使开发者能够根据业务需求灵活调整请求处理流程。

自定义中间件:日志追踪链路 ID 与 IP 白名单

在实际的 Web 应用开发中,日志追踪和 IP 白名单是两个常见的需求。日志追踪链路 ID(Trace ID)可以帮助开发者在复杂的微服务架构中追踪请求的完整路径,从而快速定位问题;而 IP 白名单则可以用于限制访问源,提高系统的安全性。通过自定义中间件,开发者可以在 FastAPI 应用中轻松实现这些功能。

日志追踪链路 ID 中间件

在分布式系统或微服务架构中,请求可能会经过多个服务组件,而传统的日志记录方式难以追踪请求的完整路径。为此,链路 ID(Trace ID)被广泛用于标识请求的生命周期。在 FastAPI 中,可以通过自定义中间件生成唯一的 Trace ID,并将其注入请求和响应头中,以便在日志中进行统一标识。

以下是一个实现日志追踪链路 ID 的中间件示例:


import uuid
from fastapi import FastAPI, Request, Response
from fastapi.middleware.base import BaseHTTPMiddleware

app = FastAPI()

class TraceIdMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        # 生成唯一的 Trace ID
        trace_id = str(uuid.uuid4())

        # 将 Trace ID 注入到请求头中,以便后续中间件或路由处理函数使用
        request.state.trace_id = trace_id

        # 打印日志,模拟日志追踪
        print(f"[Trace ID: {trace_id}] Request received: {request.url}")

        # 调用下一个中间件或路由处理函数
        response = await call_next(request)

        # 将 Trace ID 添加到响应头中,以便客户端获取
        response.headers["X-Trace-ID"] = trace_id

        # 记录响应日志
        print(f"[Trace ID: {trace_id}] Response sent: {response.status_code}")

        return response

# 将 TraceIdMiddleware 注册到 FastAPI 应用
app.add_middleware(TraceIdMiddleware)

@app.get("/")
def read_root():
    return {"message": "Request processed with trace ID."}

在上述代码中,
TraceIdMiddleware
继承自
BaseHTTPMiddleware
,并在
dispatch
方法中生成一个唯一的 Trace ID。该 Trace ID 会被注入到请求对象的
state
属性中,以便在后续的中间件或路由处理函数中使用。同时,Trace ID 也会被记录到日志中,并添加到响应头中,以便客户端获取。这种方式使得开发者可以在日志中统一标识请求的路径,从而提高系统的可观测性。

IP 白名单中间件

IP 白名单是一种常见的安全措施,用于限制特定 IP 地址或 IP 段对 API 的访问。通过自定义中间件,开发者可以在请求进入路由处理函数之前检查客户端的 IP 地址,并根据白名单决定是否允许请求继续处理。

以下是一个实现 IP 白名单的中间件示例:


from fastapi import FastAPI, Request, Response, status
from fastapi.middleware.base import BaseHTTPMiddleware
from ipaddress import ip_address, ip_network

app = FastAPI()

class IpWhitelistMiddleware(BaseHTTPMiddleware):
    def __init__(self, app, allowed_ips: list):
        super().__init__(app)
        self.allowed_ips = [ip_network(ip) if '/' in ip else ip_address(ip) for ip in allowed_ips]

    async def dispatch(self, request: Request, call_next):
        client_ip = ip_address(request.client.host)

        # 检查客户端 IP 是否在白名单中
        if not any(client_ip in ip_range for ip_range in self.allowed_ips):
            return Response(content="Forbidden", status_code=status.HTTP_403_FORBIDDEN)

        # 如果 IP 在白名单中,则继续处理请求
        response = await call_next(request)
        return response

# 注册 IP 白名单中间件,允许 IP 为 192.168.1.100 和 10.0.0.0/8
app.add_middleware(IpWhitelistMiddleware, allowed_ips=["192.168.1.100", "10.0.0.0/8"])

@app.get("/")
def read_root():
    return {"message": "Access granted."}

在上述代码中,
IpWhitelistMiddleware
接收一个
allowed_ips
参数,用于指定允许访问的 IP 地址或 IP 段。中间件会在请求处理之前检查客户端的 IP 地址是否在白名单中。如果不在白名单中,中间件将返回 403 Forbidden 错误,阻止请求的进一步处理。如果客户端 IP 在白名单中,则调用
call_next
继续请求处理流程。这种方式可以有效防止未经授权的访问,提高 API 的安全性。

通过自定义中间件,开发者可以在 FastAPI 应用中实现灵活的请求处理逻辑。无论是日志追踪链路 ID 还是 IP 白名单,都可以通过中间件的方式统一管理,提高系统的可观测性和安全性。这些自定义中间件不仅可以独立使用,还可以与其他中间件结合,构建更加复杂和完善的请求处理流程。

FastAPI 中间件的优势与应用场景

FastAPI 中间件在现代 Web 开发中具有显著优势,尤其在性能优化、安全控制和功能增强等方面表现出色。首先,中间件可以显著提升应用的性能。通过在请求和响应处理过程中插入高效的逻辑,如缓存控制、压缩响应内容或优化数据库查询,中间件能够减少不必要的计算和网络开销,从而加快请求处理速度。例如,日志追踪链路 ID 中间件可以实时记录请求路径,帮助开发者快速定位性能瓶颈,进一步优化系统运行效率。

其次,中间件在安全控制方面发挥着重要作用。通过使用 HTTPSRedirectMiddleware 和 TrustedHostMiddleware 等中间件,开发者可以强制 HTTPS 访问,防止中间人攻击,并有效限制恶意主机头攻击,确保 API 的安全性。此外,IP 白名单中间件可以进一步增强系统的访问控制,确保只有授权的 IP 地址可以访问特定资源,从而降低潜在的安全风险。

在功能增强方面,FastAPI 中间件为开发者提供了灵活的扩展能力。无论是添加自定义头、记录详细的日志信息,还是实现复杂的业务逻辑,中间件都能以最小的侵入性扩展应用的功能。例如,CORSMiddleware 的引入使得跨域请求的管理变得简单而高效,而自定义中间件的开发则能够满足个性化的需求,如链路追踪或动态路由处理。

展望未来,FastAPI 中间件将继续在 Web 开发中扮演关键角色。随着微服务架构的普及,中间件在分布式系统中的重要性将愈加凸显。通过更细粒度的控制和更强大的功能,中间件将进一步推动 Web 应用的性能提升和安全性强化。与此同时,随着云原生技术和无服务器架构的发展,FastAPI 中间件的灵活性和可扩展性也将成为开发者构建现代化应用的核心工具。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
游戏小獭的头像 - 鹿快
评论 抢沙发

请登录后发表评论

    暂无评论内容