fastapi 如何让依赖支持 yield(异步资源管理)

发布时间 - 2026-01-26 00:00:00    点击率:
FastAPI依赖中不能直接使用async def + yield,必须用@asynccontextmanager包装异步生成器;正确做法是定义异步上下文管理器,通过Depends注入,确保请求开始时初始化、响应后清理资源。

FastAPI 依赖中用 yield 会报错:TypeError: async generator object is not awaitable

直接在 FastAPI 依

赖函数里写 async def + yield 是不行的。FastAPI 默认只识别同步生成器(def + yield)或纯异步协程(async def + return),不支持异步生成器(async def + yield)。这是底层 Starlette 的限制,不是 FastAPI 的 bug。

正确写法:用 Depends 包裹 contextlib.asynccontextmanager

要让异步资源(比如 aiohttp.ClientSessionaiomysql.PoolAsyncSession)安全地生命周期绑定到请求,必须走异步上下文管理器路线。FastAPI 本身不原生解析 async with,但能识别被 asynccontextmanager 装饰后的函数。

  • 定义依赖时,用 @asynccontextmanager 包装一个 async def 函数,里面 yield 资源实例
  • 在路由中用 Depends(your_async_context_manager) 注入
  • FastAPI 会在请求开始时 await 进入上下文,在响应返回后 await 退出上下文(包括异常路径)
from contextlib import asynccontextmanager
from fastapi import Depends

@asynccontextmanager async def get_db_session(): session = AsyncSessionLocal() try: yield session finally: await session.close()

@app.get("/items/") async def read_items(db: AsyncSession = Depends(get_db_session)): return await db.execute("SELECT * FROM items")

别用 async def + yield 直接当依赖,也别手动 await 启动

以下写法全是错的:

  • async def bad_dep(): yield ... → FastAPI 不识别,抛出 TypeError
  • 试图在依赖里 await 一个 async with 块再 return → 生命周期失控,资源可能提前释放或泄漏
  • asynccontextmanager 返回的对象直接 await → 它不是协程,是上下文管理器实例

关键点在于:asynccontextmanager 把异步生成器转成了符合 ASGI 生命周期预期的上下文管理协议对象,FastAPI 内部会按需调用 __aenter____aexit__

注意嵌套依赖和作用域:scope="app" 不适用异步资源

异步资源(如数据库连接池、HTTP 客户端)通常不能设为 scope="app",因为它们需要按请求隔离或至少按任务隔离。FastAPI 的依赖作用域目前只支持 "app""request"(默认),没有 "task" 级别。

  • 如果多个请求共用一个 aiohttp.ClientSession,没问题 —— 它本就是线程/协程安全的共享对象
  • 但如果共用一个 AsyncSession,就可能引发状态污染或事务冲突
  • 所以大多数情况应保持默认 scope="request",让每个请求拿到独立的 yield 实例

真正容易被忽略的是异常传播:asynccontextmanageryield 后的代码(finally 块)一定会执行,但若 yield 期间抛出未捕获异常,__aexit__ 仍会被调用,此时你得确保清理逻辑能应对“资源处于半初始化/半失效”状态。


# mysql  # app  # session  # ai  # 路由  # 作用域  # 异步协程  # fastapi  # Object  # finally  # 线程  # 对象  # 异步  # 数据库  # http  # bug  # 管理器  # 抛出  # 的是  # 这是  # 共用一个  # 多个  # 设为  # 会在  # 要让  # 不支持 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何在云虚拟主机上快速搭建个人网站?  东莞专业网站制作公司有哪些,东莞招聘网站哪个好?  如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)  Zeus浏览器网页版官网入口 宙斯浏览器官网在线通道  Laravel如何实现数据库事务?(DB Facade示例)  5种Android数据存储方式汇总  如何在万网自助建站中设置域名及备案?  Python文件流缓冲机制_IO性能解析【教程】  Midjourney怎么调整光影效果_Midjourney光影调整方法【指南】  javascript中数组(Array)对象和字符串(String)对象的常用方法总结  javascript中的try catch异常捕获机制用法分析  Laravel如何集成第三方登录_Laravel Socialite实现微信QQ微博登录  宙斯浏览器视频悬浮窗怎么开启 边看视频边操作其他应用教程  矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?  如何用低价快速搭建高质量网站?  googleplay官方入口在哪里_Google Play官方商店快速入口指南  电视网站制作tvbox接口,云海电视怎样自定义添加电视源?  大连 网站制作,大连天途有线官网?  Laravel如何使用Facades(门面)及其工作原理_Laravel门面模式与底层机制  VIVO手机上del键无效OnKeyListener不响应的原因及解决方法  ,交易猫的商品怎么发布到网站上去?  详解阿里云nginx服务器多站点的配置  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  Laravel安装步骤详细教程_Laravel环境搭建指南  图册素材网站设计制作软件,图册的导出方式有几种?  Laravel中Service Container是做什么的_Laravel服务容器与依赖注入核心概念解析  Laravel如何升级到最新的版本_Laravel版本升级流程与兼容性处理  高端智能建站公司优选:品牌定制与SEO优化一站式服务  长沙做网站要多少钱,长沙国安网络怎么样?  阿里云高弹*务器配置方案|支持分布式架构与多节点部署  如何破解联通资金短缺导致的基站建设难题?  Laravel如何构建RESTful API_Laravel标准化API接口开发指南  Gemini手机端怎么发图片_Gemini手机端发图方法【步骤】  Laravel Sail是什么_基于Docker的Laravel本地开发环境Sail入门  如何选择可靠的免备案建站服务器?  公司门户网站制作流程,华为官网怎么做?  Android自定义listview布局实现上拉加载下拉刷新功能  深入理解Android中的xmlns:tools属性  Python3.6正式版新特性预览  武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?  高防服务器租用指南:配置选择与快速部署攻略  如何选择PHP开源工具快速搭建网站?  如何快速搭建高效香港服务器网站?  如何快速查询域名建站关键信息?  java ZXing生成二维码及条码实例分享  Laravel Eloquent模型如何创建_Laravel ORM基础之Model创建与使用教程  如何在VPS电脑上快速搭建网站?  Laravel如何安装使用Debugbar工具栏_Laravel性能调试与SQL监控插件【步骤】  Python正则表达式进阶教程_复杂匹配与分组替换解析  简单实现jsp分页