FastAPI中间件与依赖系统实战指南

文章目录

  • 前言
  • 一、什么是中间件
    • 1.1什么是中间件
    • [1.2 中间件的原理](#1.2 中间件的原理)
    • [1.3 如何实现中间件](#1.3 如何实现中间件)
    • [1.4 多中间件的执行流程](#1.4 多中间件的执行流程)
  • 二、依赖系统
    • [2.1 什么是依赖系统,为什么要用依赖系统?](#2.1 什么是依赖系统,为什么要用依赖系统?)
    • [2.2 如何实现依赖系统](#2.2 如何实现依赖系统)
  • 结语

前言

代码的优雅在于复用,架构的精妙在于分层。中间件让你掌控请求的必经之路,依赖系统让你告别重复代码。本文从拦截器模式出发,详解FastAPI两大核心机制,助你写出更干净、更可维护的后端代码。

一、什么是中间件

1.1什么是中间件

中间件是插在用户请求和API之间的一道关卡。用户的请求想要到达API,必须先经过中间件。中间件可以检查请求、修改请求,甚至直接拒绝请求。

在图片中当用户发送request请求后,会先经过m1和m2两个中间件,然后才能到达API。中间件还可以把数据发送到消息队列,或者执行定时任务。

中间件的实际应用场景包括:

  • 鉴权:判断用户是否登录

    • 认证:验证用户身份
    • 授权:判断用户有没有权限做某个操作
  • 记录日志

  • 数据清洗:检查数据是否合法

  • 限流:控制请求频率,防止服务器被压垮

    ...

1.2 中间件的原理

中间件本质上是一个拦截器。它利用了设计模式中的拦截器模式。

中间件的执行流程如下:

  1. 请求到达中间件
  2. 中间件在请求向下传递之前执行一些动作
  3. 调用await call_next(request)把请求传给下一个环节
  4. API处理完请求后,响应会原路返回
  5. 中间件在请求返回之后还可以执行一些动作

这就像你去电影院看电影:

  • 你先到检票口(中间件),检票员检查你的票
  • 票没问题,你进入影厅(API)
  • 看完电影,你原路返回,检票员还可以记录你的离场时间

1.3 如何实现中间件

在FAstAPI中,使用@app.middleware("http")装饰器来创建中间件。

python 复制代码
from fastapi import FastAPI, Request

app = FastAPI()

@app.middleware("http")
async def m1(request: Request, call_next):
    """
    中间件1
    :param request: 请求对象,包含用户请求的所有信息
    :param call_next: 将请求继续向下传递的函数
    :return: 响应对象
    """
    # 请求向下传递之前执行的动作
    print("中间件1请求向下传递之前执行了动作")

    # 将请求继续向下传递,await表示等待后续处理完成
    response = await call_next(request)

    # 请求返回之后执行的动作
    print("中间件1请求向下传递之后执行了动作")

    return response

代码详解:

  • request参数是用户的请求对象,可以读取请求头、Cookie等信息
  • call_next是一个函数,调用它会把请求传给下一个中间件或API
  • await call_next(request)是异步调用,等待后续处理完成
  • 中间件必须在最后返回response对象

1.4 多中间件的执行流程

当存在多个中间件时,它们的执行顺序是特殊的。

python 复制代码
from fastapi import FastAPI, Request

app = FastAPI()

@app.middleware("http")
async def m1(request: Request, call_next):
    print("中间件1请求向下传递之前执行了动作")
    response = await call_next(request)
    print("中间件1请求向下传递之后执行了动作")
    return response

@app.middleware("http")
async def m2(request: Request, call_next):
    print("中间件2请求向下传递之前执行了动作")
    response = await call_next(request)
    print("中间件2请求向下传递之后执行了动作")
    return response

执行顺序如下:

  1. 请求先到达m1,打印"中间件1请求向下传递之前执行了动作"
  2. m1调用call_next,请求进入m2
  3. m2打印"中间件2请求向下传递之前执行了动作"
  4. m2调用call_next,请求到达API
  5. API处理完,响应返回给m2
  6. m2打印"中间件2请求向下传递之后执行了动作"
  7. 响应返回给m1
  8. m1打印"中间件1请求向下传递之后执行了动作"

总结:多个中间件的执行顺序是"先下后上"。请求下去时先经过m1再到m2,返回时先经过m2再到m1。

这就像套娃,一层一层进去,再一层一层出来。

注意事项:

  • 中间件一旦建立,项目中所有的路由都会经过它
  • 但是可以通过判断URL路径,让某些路由走不同的逻辑

二、依赖系统

2.1 什么是依赖系统,为什么要用依赖系统?

在实际开发中,很多API需要重复执行相同的代码。比如用户管理、订单管理、会员管理这三个模块,都需要做做分页查询。每个模块都需要获取offset和limit参数,都要根据这两个参数查询数据库。但是这些模块的代码几乎是一样的。如果每个模块都写一遍,代码就会很冗余。

依赖系统就是为了解决这个问题。它把公共的代码抽成一个函数,然后在多个路由中重复使用。

依赖系统的核心思想是:

  • 复用:减少重复代码
  • 注入:把公共功能以参数的形式注入到路由函数中

2.2 如何实现依赖系统

实现依赖系统分为两步:

  1. 创建一个普通函数,这个函数就是依赖
  2. 在路由函数中使用Depends注入这个依赖
python 复制代码
from fastapi import APIRouter, Depends
from fastapi.params import Query

dependency_router = APIRouter()

# 第一步:创建依赖系统(这是一个普通的函数)
async def common_page(
    offset: int = Query(0, description="分页偏移量"),
    limit: int = Query(10, description="分页数量")
):
    """
    这个函数接收分页参数,返回分页信息
    它可以在多个路由中重复使用
    """
    return {
        "offset": offset,
        "limit": limit
    }

# 第二步:在路由中使用Depends注入依赖
@dependency_router.get("/page/")
async def get_user_page_list(common = Depends(common_page)):
    """
    common参数会自动接收common_page函数的返回值
    """
    print(common)  # 打印: {'offset': 0, 'limit': 10}
    return {
        "message": "获取用户分页列表成功"
    }
    

代码详解:

  • common_page是一个普通函数,它接收offset和limit两个查询参数
  • Query(0,description="分页偏移量")表示这是一个查询参数,默认值是0
  • Depends(common_page)告诉FAstAPI:先执行common_page函数,把它的返回值传给common参数
  • 这样get_user_page_list函数就能直接拿到分页参数,不需要自己解析

依赖系统的好处:

  1. 代码简洁:不需要在每个路由中都写参数解析
  2. 逻辑更清晰:公共逻辑抽离出来,便于维护
  3. 易于测试:依赖函数可以单独测试

更复杂的例子:

可以在依赖函数中做更多事情,比如数据库连接、权限检查等:

python 复制代码
from fastapi import APIRouter, Depends, HTTPException

dependency_router = APIRouter()

# 模拟数据库连接
async def get_db():
    db = "数据库连接对象"
    return db

# 模拟权限检查
async def check_permission(db = Depends(get_db)):
    # 检查用户是否有权限
    has_permission = True
    if not has_permission:
        raise HTTPException(status_code=403, detail="没有权限")
    return db

# 使用多个依赖
@dependency_router.get("/data/")
async def get_data(
    db = Depends(get_db),
    perm = Depends(check_permission)
):
    # 这里可以直接使用数据库连接,因为权限检查已经通过了
    return {"message": "获取数据成功"}

在这个例子中,check_permission依赖又依赖于get_db。FastAPI会自动处理这种依赖链。

结语

中间件是守门人,依赖系统是组装线。掌握它们,你就掌握了代码复用的精髓。把这些模式用熟,你的项目会少一半重复代码,多一倍清晰逻辑。继续写代码,继续优化,我们下篇再见。

相关推荐
Li emily3 小时前
股票api接口类型全解:实时行情、历史数据与技术指标
人工智能·api·fastapi
Li emily14 小时前
外汇api实战:如何获取实时汇率数据并处理
人工智能·api·fastapi
8Qi81 天前
RabbitMQ高级篇:消息可靠性、幂等性与延迟消息
java·分布式·微服务·中间件·rabbitmq·springcloud
fuquxiaoguang1 天前
中间件行业产品市场洞察报告 – 2026年第一季度
中间件·市场洞察
深兰科技1 天前
深兰科技与宝武集团旗下钢友汇达成国际市场合作,俄罗斯、巴西、阿根廷市场同步推进
人工智能·django·fastapi·pygame·httpx·视觉大模型·深兰科技
fuquxiaoguang1 天前
灰度·熵减·长期主义:任正非心智模型下的中国中间件技术突围与未来
中间件·任正非
qq_283720052 天前
Python Celery + FastAPI + Vue 全栈异步任务实战
vue.js·python·fastapi
呱牛do it2 天前
企业级绩效考核系统设计与实现:基于FastAPI + Vue3的全栈解决方案
python·fastapi
曲幽2 天前
我用fastapi-scaff搭了个项目,两天工期缩到两小时,老板以为我开挂了
python·api·fastapi·web·celery·cli·db·alembic·fastapi-scaff