FastAPI中间件实战:从基础到高级应用

爱吃面的喵

1. 什么是FastAPI中间件

中间件是Web开发中一个非常重要的概念,它就像是你家门前的一道安检门,所有进出的人(请求和响应)都要经过它的检查和处理。在FastAPI中,中间件是一个能够在请求到达路由处理器之前和/或响应返回客户端之前执行操作的组件。

想象一下这样的流程:当一个HTTP请求到达你的FastAPI应用时,它会先经过一系列中间件,就像通过一道道安检门。每个中间件都可以对请求进行检查、修改或者添加额外信息。处理完请求后,响应在返回给客户端之前,又会反向经过这些中间件,让它们有机会对响应进行处理。

下面是一个最简单的FastAPI中间件示例:

python复制from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import uvicorn

app = FastAPI()

@app.middleware("http")
async def simple_middleware(request: Request, call_next):
    # 请求处理前的操作
    print(f"收到请求: {request.method} {request.url}")
    
    # 调用下一个中间件或路由处理器
    response = await call_next(request)
    
    # 响应返回前的操作
    if isinstance(response, JSONResponse):
        response.headers["X-Processed-By"] = "SimpleMiddleware"
    print(f"处理完成: {response.status_code}")
    
    return response

@app.get("/")
async def root():
    return {"message": "Hello World"}

if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=8000)

这个简单的中间件做了三件事:在请求到达时打印日志,调用下一个处理环节,在响应返回前添加自定义头部。这就是中间件的基本工作模式。

中间件在FastAPI中有很多实际应用场景,比如记录请求日志、认证和授权、修改响应内容、性能监控、跨域资源共享(CORS)处理等。它们就像是应用的门卫、记录员和质检员,各司其职但又协同工作。

2. 常用内置中间件实战

2.1 CORSMiddleware:跨域资源共享处理

在现代Web开发中,前端和后端经常部署在不同的域名下,这就涉及跨域问题。CORSMiddleware就是FastAPI提供的解决跨域问题的利器。

跨域问题的本质是浏览器的同源策略限制。简单来说,浏览器不允许一个域下的网页脚本直接访问另一个域的资源。这是出于安全考虑,但给开发带来了不便。

CORSMiddleware的使用非常简单:

python复制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,
    allow_methods=["*"],  # 允许所有HTTP方法
    allow_headers=["*"],  # 允许所有头部
)

@app.get("/")
async def main():
    return {"message": "Hello World"}

这个配置允许来自http://localhost:3000的跨域请求,支持所有HTTP方法和头部。在实际项目中,你应该根据需求精确配置允许的源、方法和头部,而不是简单地使用通配符"*",这能更好地保障应用安全。

2.2 GZipMiddleware:响应压缩优化

网络传输中,数据压缩能显著减少传输量,提高响应速度。GZipMiddleware就是用来自动压缩HTTP响应的中间件。

python复制from fastapi import FastAPI
from fastapi.middleware.gzip import GZipMiddleware

app = FastAPI()

# 添加GZip中间件,默认只压缩大于1000字节的响应
app.add_middleware(GZipMiddleware, minimum_size=1000)

@app.get("/large-data")
async def get_large_data():
    # 返回一个大的JSON响应
    return {"data": [str(i) for i in range(10000)]}

这个中间件会自动检测客户端是否支持gzip压缩(通过Accept-Encoding头部),如果支持就会对响应进行压缩。注意,对于已经是压缩格式的内容(如图片、视频),再次压缩可能反而会增加体积,所以中间件默认会跳过这些类型。

2.3 TrustedHostMiddleware:主机头验证

这个中间件用于验证请求的Host头部,防止主机头攻击。它可以确保你的应用只处理来自可信域名的请求。

python复制from fastapi import FastAPI
from starlette.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"}

如果请求的Host头部不在允许列表中,中间件会返回400 Bad Request响应。这在生产环境中是很有用的安全措施。

3. 自定义中间件开发

3.1 基础自定义中间件

除了使用内置中间件,我们经常需要开发自己的中间件。FastAPI基于Starlette,所以自定义中间件的方式与Starlette一致。

下面是一个记录请求处理时间的中间件:

python复制import time
from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware

class TimingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        start_time = time.time()
        response = await call_next(request)
        process_time = time.time() - start_time
        response.headers["X-Process-Time"] = str(process_time)
        return response

app = FastAPI()
app.add_middleware(TimingMiddleware)

@app.get("/")
async def root():
    return {"message": "Hello World"}

这个中间件会在响应头中添加X-Process-Time,记录请求处理耗时。BaseHTTPMiddleware是Starlette提供的基类,它简化了中间件的开发。

3.2 带配置的自定义中间件

有时我们需要可配置的中间件。下面是一个限流中间件的例子,可以配置每个IP的请求频率限制:

python复制from fastapi import FastAPI, Request, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import JSONResponse
import time

class RateLimitMiddleware(BaseHTTPMiddleware):
    def __init__(self, app, max_requests: int, time_window: int):
        super().__init__(app)
        self.max_requests = max_requests
        self.time_window = time_window
        self.request_counts = {}

    async def dispatch(self, request: Request, call_next):
        client_ip = request.client.host
        current_time = time.time()
        
        if client_ip in self.request_counts:
            if current_time - self.request_counts[client_ip]["timestamp"] > self.time_window:
                self.request_counts[client_ip] = {"count": 1, "timestamp": current_time}
            else:
                self.request_counts[client_ip]["count"] += 1
                if self.request_counts[client_ip]["count"] > self.max_requests:
                    return JSONResponse(
                        status_code=429,
                        content={"error": "Too many requests"}
                    )
        else:
            self.request_counts[client_ip] = {"count": 1, "timestamp": current_time}
            
        return await call_next(request)

app = FastAPI()
app.add_middleware(RateLimitMiddleware, max_requests=5, time_window=60)

@app.get("/")
async def root():
    return {"message": "Hello World"}

这个中间件限制每个IP每分钟最多5次请求。当超过限制时,返回429 Too Many Requests响应。

3.3 修改响应的中间件

中间件不仅可以读取响应,还可以修改它。下面是一个统一修改JSON响应格式的中间件:

python复制from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import JSONResponse

class ResponseFormatterMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        response = await call_next(request)
        
        if isinstance(response, JSONResponse):
            original_content = response.body.decode()
            formatted_content = {
                "success": True,
                "data": original_content,
                "timestamp": int(time.time())
            }
            return JSONResponse(
                content=formatted_content,
                status_code=response.status_code,
                headers=dict(response.headers)
            )
            
        return response

app = FastAPI()
app.add_middleware(ResponseFormatterMiddleware)

@app.get("/")
async def root():
    return {"message": "Hello World"}

这个中间件将所有JSON响应包装成统一格式,添加了success标志和时间戳。这在API开发中很有用,可以保持响应格式的一致性。

4. 高级应用与最佳实践

4.1 中间件执行顺序

中间件的执行顺序很重要,它遵循"先进后出"的栈原则。先添加的中间件会先处理请求,但后处理响应。

python复制from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware

class MiddlewareA(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        print("MiddlewareA: before request")
        response = await call_next(request)
        print("MiddlewareA: after response")
        return response

class MiddlewareB(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        print("MiddlewareB: before request")
        response = await call_next(request)
        print("MiddlewareB: after response")
        return response

app = FastAPI()
app.add_middleware(MiddlewareA)  # 先添加
app.add_middleware(MiddlewareB)  # 后添加

@app.get("/")
async def root():
    print("Handler processing")
    return {"message": "Hello World"}

执行这个示例,你会看到输出顺序是:

code复制MiddlewareA: before request
MiddlewareB: before request
Handler processing
MiddlewareB: after response
MiddlewareA: after response

4.2 性能优化技巧

中间件虽然强大,但过度使用会影响性能。以下是一些优化建议:

  1. 只在必要时使用中间件,避免不必要的处理
  2. 将耗时的操作(如数据库查询)放在路由处理中,而不是中间件
  3. 使用异步中间件,避免阻塞操作
  4. 在生产环境中禁用调试和日志中间件
python复制import os
from fastapi import FastAPI
from .middlewares import DebugMiddleware, LoggingMiddleware

app = FastAPI()

if os.getenv("ENV") == "development":
    # 只在开发环境添加调试中间件
    app.add_middleware(DebugMiddleware)
    app.add_middleware(LoggingMiddleware)

4.3 错误处理策略

中间件中的错误需要特别处理,因为它们不会自动被FastAPI的错误处理器捕获。

python复制from fastapi import FastAPI, Request, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import JSONResponse

class ErrorHandlerMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        try:
            return await call_next(request)
        except HTTPException as http_exc:
            return JSONResponse(
                content={"error": http_exc.detail},
                status_code=http_exc.status_code
            )
        except Exception as exc:
            # 记录详细错误信息
            print(f"Unexpected error: {exc}")
            return JSONResponse(
                content={"error": "Internal Server Error"},
                status_code=500
            )

app = FastAPI()
app.add_middleware(ErrorHandlerMiddleware)

@app.get("/error-test")
async def error_test():
    raise ValueError("Something went wrong")

这个错误处理中间件可以捕获各种异常,并返回适当的响应。注意在生产环境中,你应该使用更完善的日志记录系统。

4.4 状态共享技巧

中间件和路由处理器之间经常需要共享状态。可以使用request.state来实现:

python复制from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware
import uuid

class RequestIDMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        request.state.request_id = str(uuid.uuid4())
        response = await call_next(request)
        response.headers["X-Request-ID"] = request.state.request_id
        return response

app = FastAPI()
app.add_middleware(RequestIDMiddleware)

@app.get("/")
async def root(request: Request):
    return {"request_id": request.state.request_id}

这个中间件为每个请求生成唯一ID,并通过request.state共享给路由处理器,同时在响应头中返回这个ID。这在分布式系统中特别有用,便于追踪请求链路。

内容推荐

图解算法:深度优先搜索(DFS)在社交网络关系分析中的应用
本文深入探讨了深度优先搜索(DFS)算法在社交网络关系分析中的应用,详细介绍了如何利用DFS挖掘潜在社交关系并构建好友推荐系统。通过图结构建模、DFS算法优化及推荐权重计算模型,帮助开发者高效实现社交网络分析功能,提升好友推荐的准确性和效率。
【运筹学】互补松弛定理实战解析:从理论到应用的完整指南
本文深入解析运筹学中的互补松弛定理,从理论到实战应用全面指导。通过玩具厂生产优化和电商仓储案例,详细展示如何利用互补松弛性协调原问题与对偶问题的最优解,验证资源分配效率。文章还提供常见误区分析和Python验证工具,帮助读者掌握这一线性规划核心理论。
Python实战:解密并下载HLS加密流媒体m3u8视频的完整指南
本文详细介绍了如何使用Python解密并下载HLS加密流媒体m3u8视频的完整指南。从理解HLS流媒体与m3u8加密机制到实战环境搭建、密钥获取、AES解密及高效下载合并,提供了全面的技术方案和代码实现,帮助开发者快速掌握流媒体下载技术。
OpenHarmony 5.1.0基线移植保姆级教程:从开源仓到私有仓的完整避坑指南
本文详细解析了OpenHarmony 5.1.0基线移植到私有仓库的全流程,包括环境准备、源码获取、私有仓库初始化、代码移植核心流程、编译验证与提交规范等关键步骤。通过实战案例和避坑指南,帮助开发者高效完成OpenHarmony移植工作,提升企业私有化部署效率。
从PatchCore到FastFlow:一文读懂Anomalib里7大异常检测算法的适用场景与选型指南
本文深入解析Anomalib生态系统中七大异常检测算法(如PatchCore和FastFlow)的适用场景与选型策略。通过工业质检实例和技术参数对比,帮助开发者根据纹理背景、结构背景等不同需求选择最优算法,提升图像异常检测效率与精度。
手把手教你用Docker Compose在单机快速搭建Gitlab+Jenkins+Harbor开发测试环境(避坑指南)
本文详细介绍了如何使用Docker Compose在单机上快速搭建GitLab+Jenkins+Harbor开发测试环境,提供完整的docker-compose.yml配置和优化技巧。涵盖服务集成、自动化流程配置以及日常维护指南,帮助开发者高效构建轻量化CI/CD工具链,特别适合个人开发者和小型团队。
【RocketMQ】mqadmin运维实战:从零到一掌握核心管理命令
本文详细介绍了RocketMQ的mqadmin运维管理命令,从主题管理、消息查询到消费者组监控和集群运维,提供了全面的实操指南。通过具体案例和命令示例,帮助运维工程师快速掌握核心管理命令,提升RocketMQ的运维效率。
Qt/C++实战:手把手教你用GB28181组件对接海康大华摄像头(含云台控制与录像回放)
本文详细介绍了如何使用Qt/C++开发GB28181组件对接海康、大华摄像头,涵盖云台控制与录像回放等核心功能。通过实战代码示例和参数对照表,解决设备注册、视频点播、PTZ控制等典型问题,并提供性能优化方案,帮助开发者快速实现安防监控系统集成。
Cadence仿真进阶:参数扫描在直流与瞬态分析中的实战应用
本文深入探讨了Cadence仿真中参数扫描在直流与瞬态分析中的实战应用。通过参数扫描技术,工程师可以高效分析电路静态工作点和动态响应,优化设计性能。文章详细介绍了从创建参数化电路到配置扫描分析的完整流程,并分享了多参数交叉验证、工艺角扫描等高级技巧,帮助读者提升电路设计效率与准确性。
C++模板元编程实战指南:从基础到高阶技巧
本文深入探讨C++模板元编程从基础到高阶的实战技巧,涵盖编译期计算、类型推导、SFINAE、变参模板等核心概念,并结合C++17新特性如折叠表达式进行实例解析。通过类型系统设计、字符串处理优化等案例,展示如何利用模板元编程提升性能与代码质量,同时讨论其边界与现代替代方案如concept的应用。
STM32f103 密码锁实战:从零搭建硬件与核心逻辑(一)
本文详细介绍了基于STM32f103的密码锁项目实战,从硬件选型、连接技巧到软件开发环境搭建和核心功能实现。通过优化按键扫描、Flash存储方案及常见问题排查,帮助开发者快速掌握嵌入式密码锁开发技术,适用于安防系统和智能门锁等应用场景。
SPI vs I2C:为你的Arduino或STM32项目选择OLED驱动接口,看完这篇不再纠结
本文详细对比了SPI和I2C两种接口协议在驱动OLED显示屏时的优缺点,帮助开发者为Arduino或STM32项目选择合适的通信接口。从通信机制、硬件资源占用、实际性能到开发复杂度,全面分析SPI和I2C的适用场景,并提供选型决策树,助您轻松做出最佳选择。
转义字符实战指南:从基础到常见问题解析
本文深入解析转义字符的本质与作用,从基础概念到实际应用场景全面覆盖。通过11个核心转义字符的详细讲解和常见问题解析,帮助开发者避免常见陷阱,提升编程效率。特别针对文件路径处理、正则表达式等场景提供实用解决方案,并分享调试转义字符问题的专业技巧。
实战指南 | Oracle19c在Redhat环境下的高效安装与配置全解析
本文详细解析了Oracle19c在Redhat环境下的高效安装与配置全流程,涵盖环境准备、系统参数优化、用户与目录规划、软件安装、数据库创建等关键步骤。通过实战经验分享,帮助读者避开常见陷阱,提升安装效率与数据库性能,特别适合需要快速部署Oracle19c的DBA和系统管理员。
别再只用pd.to_datetime了!Pandas DataFrame日期列转换的3种方法性能实测与避坑指南
本文深入评测了Pandas DataFrame日期列转换的3种主流方法:`astype('datetime64')`、`pd.to_datetime`和`datetime.strptime`,揭示其性能差异与适用场景。通过百万行数据实测,发现`astype`速度最快但格式兼容性差,`pd.to_datetime`全能但有隐藏成本,`strptime`灵活但性能低下。文章还提供了处理混合格式、时间戳精度陷阱及内存优化的实用技巧,帮助开发者根据数据特征选择最优方案。
C# Chart控件性能调优笔记:除了分段加载,还有哪些提升渲染速度的技巧?
本文深入探讨了C# Chart控件在面临数据量过大时的性能优化技巧,包括控件层级的精简配置、高效数据绑定方法和渲染管线的深度优化。通过实战案例,展示了如何从底层代码到架构升级全面提升渲染速度,解决卡顿问题,实现千万级数据点的流畅可视化。
手把手教你用Python测试串口助手的中文兼容性(SSCOM实测)
本文详细介绍了如何使用Python测试SSCOM串口助手的中文兼容性,涵盖GB2312、GBK和UTF-8等编码的实战测试方案。通过构建自动化测试框架和提供优化建议,帮助开发者解决串口通信中的中文乱码问题,提升硬件调试效率。
从算法到芯片:红外非均匀校正的两点定标法在ASIC设计中的实现考量
本文深入探讨了红外非均匀校正的两点定标法在ASIC设计中的实现考量,重点分析了算法硬件适配性、内存访问规律性及低功耗设计技巧。通过优化存储架构和计算单元并行度,实现了高效能、低功耗的ASIC解决方案,适用于安防监控和工业检测等场景。
Spartan-6 FPGA配置模式实战选型指南:从理论到硬件连接
本文深入解析Spartan-6 FPGA的芯片配置模式,包括JTAG、Serial、SelectMAP、SPI和BPI五种主流方式,提供从理论到硬件连接的实战指南。通过详细对比主从模式特点、配置速度、硬件复杂度等维度,帮助工程师根据应用场景选择最优方案,并分享工业级项目的避坑经验与高级技巧。
嵌入式Linux--U-Boot(二)实战命令解析与调试技巧
本文深入解析嵌入式Linux系统中U-Boot的实战命令与调试技巧,涵盖命令行模式进入、信息查询命令、环境变量操作、内存调试等核心内容。通过具体案例分享,帮助开发者掌握U-Boot调试的关键技术,提升嵌入式系统开发效率。
已经到底了哦
精选内容
热门内容
最新内容
1045 - Access Denied for User 'root'@'%': MySQL远程连接权限配置全解析
本文详细解析了MySQL远程连接时常见的1045错误(Access denied for user 'root'@'%'),深入剖析了MySQL权限体系和安全机制,并提供了从Navicat配置到命令行操作的全套解决方案。通过实际案例演示如何平衡安全性与便利性,包括创建专用账户、限制root访问、启用SSL等企业级安全实践,帮助开发者高效解决远程连接权限问题。
智能车竞赛WiFi图传避坑指南:用逐飞库和MT9V03X摄像头,我踩过的那些坑
本文详细介绍了智能车竞赛中WiFi图传系统的优化实践,重点解析了基于逐飞库和MT9V03X摄像头的避坑指南。从硬件选型到图像传输协议优化,再到实时性保障和抗干扰处理,提供了完整的解决方案和实战代码示例,帮助参赛团队构建稳定的图传系统。
保姆级教程:在Ubuntu 22.04 + ROS2 Humble中,为单个工作空间定制OpenCV 4.10.0环境
本文提供在Ubuntu 22.04 + ROS2 Humble环境中为单个工作空间定制OpenCV 4.10.0的保姆级教程。通过源码编译、CMake配置和ROS2集成方案,实现与系统OpenCV版本的完全隔离,满足计算机视觉开发中对最新算法和DNN模块的需求。
Prompt工程实战:5个技巧让你的ChatGPT输出更精准(附案例对比)
本文深入探讨了Prompt工程的5个实战技巧,帮助用户显著提升ChatGPT输出的精准度。通过结构化框架、信息密度控制、案例对比、温度参数调节和角色扮演等方法,结合具体案例展示了优化前后的显著差异。文章特别强调精准Prompt设计的重要性,并提供了避免常见错误的实用建议,助力用户高效生成符合需求的内容。
【Conda】从新手到专家:环境隔离与依赖管理的核心命令全解析
本文全面解析Conda环境隔离与依赖管理的核心命令,从创建、激活环境到包管理、版本控制,再到环境配置的导出与共享。通过实用技巧和最佳实践,帮助开发者高效管理Python项目依赖,避免冲突,提升工作效率。特别适合需要处理多项目、多版本依赖的Python开发者。
Surface Go 4+64G 低配版,我是如何用它搞定Python、LaTeX和C++的完整开发环境
本文分享了如何在Surface Go 4+64G低配版上搭建高效的Python、LaTeX和C++开发环境。通过系统优化、轻量级工具选择和配置技巧,即使在硬件限制下也能保持生产力。文章详细介绍了Python开发环境配置、LaTeX写作环境搭建、C++开发工具链选择以及版本控制优化方案,为预算有限的开发者和学生提供实用指南。
【ESP32+MPU6050 DMP实战】PlatformIO移植避坑与姿态数据可视化
本文详细介绍了在PlatformIO环境下将MPU6050 DMP功能移植到ESP32的实战经验,包括I2C通信优化、DMP初始化配置及姿态数据可视化技巧。针对ESP32与Arduino的差异,提供了关键代码修改方案和常见问题解决方案,帮助开发者高效实现精准姿态检测。
投稿前必看:避开这些坑,你的参考文献格式才算真的规范了
本文详细解析科研论文投稿中参考文献格式的常见问题与规范要求,涵盖期刊缩写规则、文献管理软件使用技巧及五大格式雷区。特别针对Elsevier、Springer等出版社的特例进行分析,提供实用的核查清单,帮助研究者避免因格式问题导致的投稿延误。
【实战指南】IST8310磁力计在RoboMaster开发板上的数据采集与处理
本文详细介绍了IST8310磁力计在RoboMaster开发板上的数据采集与处理实战指南。从硬件认知到开发环境搭建,再到寄存器配置与数据采集,提供了完整的操作流程和优化技巧,帮助开发者高效实现磁场数据读取与处理,适用于机器人竞赛等实时性要求高的场景。
Unity3D UGUI合批实战:从规则解析到性能调优
本文深入解析Unity3D UGUI合批机制,从规则解析到性能调优,提供实战指南和优化方案。通过Frame Debugger和Profiler工具分析合批中断原因,探讨材质、贴图、深度计算等关键因素,并分享图集管理、动静分离架构等高级优化策略,帮助开发者提升UI性能。