游乐游手机版
首页/业界动态/文章详情

FastAPI 依赖注入被你用成了全局变量?别慌,三分钟讲透

时间:2026-04-16 16:55
一、你可能正在这样写 先来做个自我检测,看看你的代码有没有“中招”。打开你的 FastAPI 项目,如果发现了下面任何一种写法,那么恭喜——你可能已经成功地把依赖注入用成了全局变量。 写法一:在依赖函数里塞了个列表,全项目共享状态 from fastapi import FastAPI, Depen

一、你可能正在这样写

先来做个自我检测,看看你的代码有没有“中招”。打开你的 FastAPI 项目,如果发现了下面任何一种写法,那么恭喜——你可能已经成功地把依赖注入用成了全局变量。

写法一:在依赖函数里塞了个列表,全项目共享状态

from fastapi import FastAPI, Depends

app = FastAPI()

# 这玩意儿叫“全局变量”,不叫“依赖注入”
cache = []

@app.get("/items")
async def get_items():
    cache.append("data")
    return {"cache": cache}

写法二:在路由函数里直接 import 一个单例,假装在用依赖注入

from fastapi import FastAPI, Depends

app = FastAPI()

class Database:
    def __init__(self):
        self.connection = "I'm a global db!"

db = Database()  # 这行代码,值得警惕

@app.get("/items")
async def get_items(database: Database = Depends(lambda: db)):
    return database.connection

写法三:在依赖函数里保存了上一次请求的状态

from fastapi import FastAPI, Depends

app = FastAPI()

def get_user():
    # 每次请求,上一个用户的数据还留着
    user_data = {"name": "last_user"}
    return user_data

@app.get("/profile")
async def profile(user = Depends(get_user)):
    return user

如果以上写法你都没用,那真要恭喜你:要么你是天赋异禀,要么就是项目还没真正开始。如果中了招——别慌,往下看,三分钟带你回到正轨。

二、依赖注入到底是什么

在讨论“什么错了”之前,得先搞清楚“什么是对的”。

FastAPI 的依赖注入,本质上是一个请求级别的工厂函数。每次请求到来,框架都会帮你调用一次这个“工厂”,把返回值注入到路由函数里。请求一结束,这个对象也就随之消失了。

打个比方,就像医院挂号:你去医院看病,医生让你去抽血。抽血窗口每次只服务一个病人,你抽完走了,下一个人来,护士会重新准备一套全新的工具。

依赖注入就是这个逻辑——每个请求拥有自己独立的对象,彼此互不干扰。

而全局变量则是另一回事:你抽完血走了,抽血窗口的工具还留在那儿,下一个人来了,发现里面可能还躺着上一个人的血样。

这就是 FastAPI 依赖注入的核心特征:请求隔离,自动清理

三、正确的打开方式

场景一:数据库连接(最常见)

from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session

# 每次请求进来,创建新的连接;请求结束,自动关闭
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.get("/users/{user_id}")
async def get_user(user_id: int, db: Session = Depends(get_db)):
    return db.query(User).filter(User.id == user_id).first()

关键点:这里的 yield 是精髓——yield 前面的代码在请求开始时执行,yield 后面的代码在请求结束时执行,资源清理自动完成,干净利落。

场景二:用户认证(链式依赖)

from fastapi import Depends, HTTPException

# 第一层:提取 Token
def get_token(token: str = Header(None)):
    if not token:
        raise HTTPException(status_code=401, detail="未登录")
    return token

# 第二层:验证 Token,返回用户信息
def get_current_user(token: str = Depends(get_token)):
    user = verify_jwt(token)
    if not user:
        raise HTTPException(status_code=401, detail="Token 无效")
    return user

# 在路由中使用,依赖链自动解析
@app.get("/profile")
async def profile(user = Depends(get_current_user)):
    return {"username": user.username}

关键点get_current_user 依赖 get_token,FastAPI 会自动帮你处理调用顺序,路由函数里只需要写 Depends(get_current_user) 即可,逻辑清晰,职责分明。

场景三:应用级全局依赖(跨所有路由)

from fastapi import FastAPI, Depends, Header, HTTPException

async def verify_api_key(x_api_key: str = Header(...)):
    if x_api_key != "your-secret-key":
        raise HTTPException(status_code=403, detail="API Key 不对")
    return x_api_key

# 加在 app 上,所有路由都要过这关
app = FastAPI(dependencies=[Depends(verify_api_key)])

@app.get("/items")
async def read_items():
    return [{"item": "Portal Gun"}]

@app.get("/users")
async def read_users():
    return [{"username": "Rick"}]

关键点app = FastAPI(dependencies=[...]) 是全局拦截器,所有路由都要过这一关。这非常适合添加像 API Key 校验这种“每个接口都必须有”的统一逻辑。

四、什么时候真的可以用“全局变量”

坦白说,有两种情况,使用全局变量是合理且安全的:

情况一:配置参数(不涉及请求状态)

from fastapi import FastAPI

app = FastAPI()

# 写死的配置常量,不是请求状态,完全 OK
MAX_PAGE_SIZE = 100
DEFAULT_TIMEOUT = 30

情况二:Lru_cache 缓存(读写分离,明确知道自己在干什么)

from functools import lru_cache

@lru_cache()
def get_config():
    # 应用启动时加载一次,整个进程生命周期内不变
    return load_config_from_file()

@lru_cache()
def get_redis_client():
    # 连接池,通常在应用启动时建立,不随请求创建/销毁
    return redis.Redis(host="localhost")

记住一个简单的原则:但凡涉及请求状态(用户数据、token、请求参数),就老老实实用 Depends。配置和只读的缓存,才是全局变量的主场。

五、避坑清单

来做个快速自检,看看你的项目里有没有这些“坑”:

  • 数据库连接、Redis 连接用了 global 关键字?赶紧删掉。
  • 依赖函数里存了 list 或 dict 来“暂存”数据?马上换掉。
  • 出现了 Depends(lambda: db_instance) 这种写法?这说明你在用全局变量糊弄依赖注入系统,别骗自己。
  • 每次请求需要独立的用户上下文?用链式 Depends 来解决。
  • 想给所有路由统一加校验?用 app = FastAPI(dependencies=[...]) 这个全局依赖。

六、总结

依赖注入不是什么高深莫测的概念,它就做一件事:让每个请求有自己独立的对象,用完自动清理,不用开发者操心。

把它用成全局变量,不是因为你笨,往往是因为 FastAPI 写起来太顺手了——顺手到让人忍不住想走捷径。

但捷径是有代价的:用户 A 的数据莫名其妙跑到用户 B 的响应里,这种诡异又难查的 Bug,足以让人怀疑人生。

所以,请牢记这个核心原则:依赖注入管的是“请求里的东西”,配置常量才是真正的“全局东西”。分清楚这个,你就能避开绝大多数坑。

来源:https://www.51cto.com/article/840714.html
上一篇曝小米澎湃OS3为老机型增加超级岛防烧屏算法,长时显示会变淡 下一篇我顺极了!文章回应开面馆:纯属是为了自己有一口吃的
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
九号N1机甲风电动车发布 模拟声浪轻量化车架3499元起
业界动态 · 2026-05-29

九号N1机甲风电动车发布 模拟声浪轻量化车架3499元起

九号发布N1机甲风电动车系列,三款起售价3499元。N170极速47km h,轻量化车架;N185极速55km h,可选模拟声浪;旗舰N190极速60km h,标配模拟声浪及双通道ABS,7月上市。

九号2026新品发布会最强阵容连发4款新车重新定义好车标准
业界动态 · 2026-05-29

九号2026新品发布会最强阵容连发4款新车重新定义好车标准

九号公司发布2026年新品,推出N1、M1、M3及Fz5四款新车,覆盖电摩与电自领域。N1主打短轴距声光电酷玩体验,M1配备双通道ABS与100公里真续航,M3下放AXC车架技术,Fz5首搭载双向转把功能。同时推出3年原厂换新质保等用户权益。

世界超级摩托车锦标赛阿拉贡站张雪机车超级杆位赛获亚军
业界动态 · 2026-05-29

世界超级摩托车锦标赛阿拉贡站张雪机车超级杆位赛获亚军

5月29日,世界超级摩托车锦标赛(WSBK)阿拉贡站传来一则引人瞩目的消息——中国摩托车制造商“张雪机车”旗下的法国车手瓦伦丁·德比斯,在WorldSSP组别的超级杆位赛中成功夺得第二名。 先简要科普一下赛事背景:世界超级摩托车锦标赛(WSBK)是由国际摩托车联合会于1988年创立的顶级公路摩托车赛

英雄联盟海克斯大乱斗重大更新 移除羁绊新增技能符文
业界动态 · 2026-05-29

英雄联盟海克斯大乱斗重大更新 移除羁绊新增技能符文

英雄联盟海克斯大乱斗将在26 12版本移除羁绊系统,上线技能符文体系。该符文能重构技能释放逻辑,实现布里茨钩五人、拉克丝定全队等效果。部分原有羁绊效果转为独立专属符文,更新预计2026年6月中旬登陆国服。

领克10/10+正式上市限时价16.99-23.59万号称弯道之王
业界动态 · 2026-05-29

领克10/10+正式上市限时价16.99-23.59万号称弯道之王

```html 5月29日晚间,领克终于将其备受关注的中大型运动纯电轿车正式推向市场——领克10与领克10+同步上市,官方直接打出“弯道之王”的旗号。我们先不深究它是否真能“弯道超车”,单从价格来看,就已经颇具冲击力。 先奉上一张价格速览表,让大家心里有个底: 领克 10 701 长续航 Max:指