中间件与依赖系统:构建高效 Web 后端的双重利器

文章目录

  • [一、 中间件(Middleware):全局的"拦截器"](#一、 中间件(Middleware):全局的“拦截器”)
    • [1.1 核心概念](#1.1 核心概念)
    • [1.2 执行原理](#1.2 执行原理)
    • [1.3 代码实现](#1.3 代码实现)
    • [1.4 多中间件执行顺序](#1.4 多中间件执行顺序)
  • [二、 依赖系统(Dependency Injection):精细化的"业务注入"](#二、 依赖系统(Dependency Injection):精细化的“业务注入”)
    • [2.1 为什么要用依赖系统?](#2.1 为什么要用依赖系统?)
    • [2.2 如何实现依赖?](#2.2 如何实现依赖?)
  • 三、如何实现"局部中间件"?
  • [四、 注意注意注意注意注意](#四、 注意注意注意注意注意)

一、 中间件(Middleware):全局的"拦截器"

1.1 核心概念

中间件是一个在每个 请求 (Request) 被处理之前,以及每个 响应 (Response) 返回之前运行的函数。它是全局性的,一旦建立,项目中的所有路由都会经过它。

1.2 执行原理

中间件通过 call_next 建立起请求的传递链:

1、前置处理:请求向下传递(交给路由)之前执行。

2、传递请求:调用 await call_next(request)

3、后置处理:路由处理完后,在响应返回给客户端之前执行。

1.3 代码实现

main.py 中直接定义(注意:APIRouter 不支持直接定义中间件):

python 复制代码
@app.middleware("http")
async def process_timer(request: Request, call_next):
    # 【前置】记录请求开始时间
    print("中间件:开始拦截请求")
    
    response = await call_next(request)
    
    # 【后置】添加自定义响应头或日志
    print("中间件:准备返回结果")
    return response

1.4 多中间件执行顺序

当有多个中间件时,执行顺序是从下向上(或者说后定义的先执行请求,先定义的后处理响应)。

二、 依赖系统(Dependency Injection):精细化的"业务注入"

2.1 为什么要用依赖系统?

如果说中间件是"强迫所有人过安检",那么依赖系统就是"谁需要谁申请"。

假设你写了两个接口:一个是"查看个人资料",一个是"修改个人资料"。这两个接口都需要先验证用户是否登录。

这时候,你写一个验证函数作为"依赖项",谁需要验证,谁就在参数里"领取"它。

2.2 如何实现依赖?

python 复制代码
# 1. 定义一个依赖项
async def verify_token(token: str):
    if token != "secret-key":
        return {"error": "暗号不对,不准入内"}
    return "验证通过"

# 2. 在需要的路由里"领取"它
@user_router.get("/info/")
async def get_user_info(auth_status = Depends(verify_token)):
    # 只有 verify_token 成功了,才会执行这里
    return {"status": auth_status, "name": "Chang Yang"}

三、如何实现"局部中间件"?

中间件一旦建立,所有路由都得走,能不能让某些路由走,某些不走?
答案是:当然能!!!

在 FastAPI 里,这通常有两种实现方案:

  • Plan A:在中间件内部做排除(白名单)
    在中间件函数里加个判断:
python 复制代码
@app.middleware("http")
async def selective_middleware(request: Request, call_next):
    # 定义不需要走中间件的路径
    white_list = ["/login", "/register", "/docs"]
    
    if request.url.path in white_list:
        return await call_next(request) # 直接放行,不走下面的逻辑
    
    # 下面是正常的拦截逻辑...
    print("正在拦截受保护的路径")
    return await call_next(request)
  • Plan B:使用"依赖注入"模拟局部中间件
    部分代码示例(这里是一个单独的py文件):
python 复制代码
import time
# 用依赖系统上实现局部中间件
# 第一步:定义一个依赖函数
async def my_timer_dep():
    start_time = time.time()
    yield
    process_time = time.time() - start_time
    print("接口耗时:", process_time, "秒")
python 复制代码
from fastapi import Depends
# 导入依赖函数
from aps.Common.deps import my_timer_dep
@api_router.get('/{id}',dependencies=[Depends(my_timer_dep)])
async def get_user(id: int):
    return {
        'id': id,
        'name': '张三'
    }

四、 注意注意注意注意注意

  • 路径斜杠问题:在定义带有查询参数的路径时,结尾建议加上 /。虽然某些 AI 或文档说不加也能跑,但在标准 RESTful 实践和 FastAPI 的某些配置下,加斜杠能避免不必要的重定向问题。
  • 异步避坑:如果你在中间件里处理文件或耗时 I/O,一定要记得使用 await,否则会阻塞整个异步循环。
相关推荐
顾林海2 小时前
Agent入门阶段-编程基础-Python:流程控制
python·agent·ai编程
呱呱复呱呱5 小时前
Django CBV 源码解读:一个请求是怎么找到你的 get() 方法的
python·django
曲幽10 小时前
刚部署的 LibreTranslate 频频翻车?我掏出了 20 年前的 StarDict 词典,用 FastAPI 搭了个本地词典翻译 API
python·fastapi·web·translate·goldendict·libretranslate·stardict·pystardict
荣码10 小时前
用Streamlit给AI应用套个界面,10行代码出Web页面
java·python
兵慌码乱20 小时前
基于Python+PyQt5+SQLite的药房管理系统实现:事务一致性与界面解耦全流程解析
python·sqlite·信号与槽·pyqt5·数据库设计·桌面应用开发·事务处理
金銀銅鐵21 小时前
[Python] 体验用欧几里得算法计算最大公约数的过程
python·数学
FreakStudio1 天前
W55MH32L-EVB 上手测评:硬件 TCP/IP 加持的以太网单片机,MicroPython 零门槛开发
python·单片机·嵌入式·大学生·面向对象·并行计算·电子diy·电子计算机
用户0332126663671 天前
使用 Python 从零创建 Word 文档
python
Csvn1 天前
Python 两大经典坑点 —— 可变默认参数 & 闭包延迟绑定
后端·python
曲幽1 天前
别再用网页翻译看源码了!你的私人翻译神器LibreTranslate,部署避坑指南来了
python·docker·web·pot·translate·libretranslate·arogstranslate