中间件与依赖系统:构建高效 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,否则会阻塞整个异步循环。
相关推荐
心中有国也有家18 分钟前
GE图引擎深度解析——CANN的计算图优化与执行引擎
人工智能·pytorch·python·学习·numpy
卷毛的技术笔记2 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
编程大师哥2 小时前
匿名函数 lambda + 高阶函数
java·python·算法
isyangli_blog2 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008112 小时前
FastAPI APIRouter
开发语言·python
Benszen2 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆2 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木2 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
adrninistrat0r2 小时前
Java调用链MCP分析工具
java·python·ai编程
杨充2 小时前
1.3 浮点型数据设计灵魂
开发语言·python·算法