FastAPI中,如何让中间件、依赖和路由协同共享状态秘籍?
摘要:深入浅出讲解FastAPI中Request.state的用法,通过一个用户画像的实战案例,带你彻底搞懂如何在中间件、依赖项和路由处理程序之间优雅地共享数据。告别全局变量,拥抱更安全、更清晰的数据传递方式。
你是不是也遇到过这种场景:在中间件里好不容易解析出了用户ID,到了路由处理函数里,却还得再查一遍数据库?或者依赖项里计算好的权限信息,想传递给后续业务逻辑,只能吭哧吭哧用全局变量?
🎯 今天咱们就聊聊FastAPI里那个低调却强大的 Request.state 存储机制。我用一个真实的“用户画像”案例,带你走一遍从踩坑到优雅解决的全过程。保证你看完,就能让中间件、依赖和路由处理程序之间“手拉手”愉快地共享数据!
📌 本文将带你搞懂:
- 为什么全局变量是“毒药”?
- Request.state 的正确打开方式
- 一个完整的实战:在中间件中注入用户信息,通过依赖传递,最后在路由中使用。
- 避坑指南:State的生命周期、并发安全性,以及和Contextvar的恩怨情仇。
🍜 故事从一碗牛肉面说起
想象一下,你开了一家牛肉面馆。每个客人进来,你都得先问“要辣吗?”“要香菜吗?”。这个收集信息的过程,就像是 中间件。然后后厨根据这些信息,决定放多少辣、加不加香菜,这就像 依赖项。最后,一碗定制化的面端到客人面前,这就是 路由处理程序。
如果你把“加辣”、“加香菜”这些信息写在收银台的一张公共小黑板上(全局变量),那当两个客人同时点餐时,后厨肯定会看花眼,把A客人的辣面端给B客人。这就是并发下的数据混乱!
FastAPI 的 Request.state 就相当于给每个客人发了一张专属的“点餐小票”,从收银台到后厨,这张小票全程跟着这碗面,绝对不会搞混。
🚀 实战:给每个请求贴上“用户画像”
好,不废话了,咱们直接上代码。假设我们有一个场景:需要从请求头中获取用户令牌,解析出用户信息,然后在后续的所有逻辑中都能用到这个用户信息。
1️⃣ 最傻最暴力的错误示范
# 全局变量,并发地狱的入口
current_user = None
@app.middleware("http")
async def add_user_middleware(request, call_next):
global current_user
token = request.headers.get("Authorization")
# 模拟解析用户
current_user = {"id": 1, "name": "张三"}
response = await call_next(request)
return response
@app.get("/profile")
async def get_profile():
# 直接读取全局变量,多个请求会相互覆盖!!!
return current_user
这里千万别学这种偷懒写的代码,否则半夜收到报警短信,说用户A看到了用户B的隐私信息,那就只能等着哭了。😭 全局变量在并发请求下就是个定时炸弹。
2️⃣ 优雅的救世主:Request.state
接下来重点来了!FastAPI 的 request.state 才是我们想要的“点餐小票”。它依附于每一个独立的请求对象,天然就是线程/协程安全的。
