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 才是我们想要的“点餐小票”。它依附于每一个独立的请求对象,天然就是线程/协程安全的。
阅读全文