You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask中TypeError:'async_generator' object is not iterable问题排查

Flask搭建Telegram文件流服务的异步生成器报错问题解决

我尝试在Flask中搭建Telegram文件流服务,核心代码如下:

from flask import Response

@app.route("/dl/<hash>", methods=["GET"])
async def download(hash):
    body = yield_file()
    return Response(
        status=206 if range_header else 200,
        response=body,
        headers={
            "Content-Type": f"{mime_type}",
            "Content-Range": f"bytes {from_bytes}-{until_bytes}/{file_size}",
            "Content-Length": str(req_length),
            "Content-Disposition": f'{disposition}; filename="{file_name}"',
            "Accept-Ranges": "bytes",
        },
    )

其中yield_file()是一个异步生成器函数,在原项目的aiohttp服务器中运行正常,但迁移到Flask后出现以下报错:

127.0.0.1 - - [03/Aug/2023 22:21:06] "GET /dl/jRtYoKqEu6 HTTP/1.1" 500 -
Error on request:
Traceback (most recent call last):
  File "C:\Users\hp\AppData\Roaming\Python\Python310\site-packages\werkzeug\serving.py", line 364, in run_wsgi       
    execute(self.server.app)
  File "C:\Users\hp\AppData\Roaming\Python\Python310\site-packages\werkzeug\serving.py", line 327, in execute        
    for data in application_iter:
  File "C:\Users\hp\AppData\Roaming\Python\Python310\site-packages\werkzeug\wsgi.py", line 289, in __next__
    return self._next()
  File "C:\Users\hp\AppData\Roaming\Python\Python310\site-packages\werkzeug\wrappers\response.py", line 32, in _iter_encoded
    for item in iterable:
TypeError: 'async_generator' object is not iterable

问题原因

你的怀疑完全正确:Flask默认基于WSGI协议,Werkzeug(Flask的底层WSGI工具库)在处理响应体时,使用同步for循环遍历迭代对象,但yield_file()是异步生成器,只能通过async for语法遍历,两者不兼容,因此抛出类型错误。

解决方法

方法1:将异步生成器转为同步迭代器

通过异步IO工具把异步生成器包装成同步迭代器,让Werkzeug可以正常遍历:

import asyncio
from flask import Response

def sync_wrap_async_gen(async_gen):
    """把异步生成器转为同步迭代器"""
    loop = asyncio.get_event_loop()
    async def get_next():
        try:
            return await async_gen.__anext__(), False
        except StopAsyncIteration:
            return None, True
    while True:
        item, done = loop.run_until_complete(get_next())
        if done:
            break
        yield item

@app.route("/dl/<hash>", methods=["GET"])
async def download(hash):
    body = sync_wrap_async_gen(yield_file())  # 包装异步生成器
    return Response(
        status=206 if range_header else 200,
        response=body,
        headers={
            "Content-Type": f"{mime_type}",
            "Content-Range": f"bytes {from_bytes}-{until_bytes}/{file_size}",
            "Content-Length": str(req_length),
            "Content-Disposition": f'{disposition}; filename="{file_name}"',
            "Accept-Ranges": "bytes",
        },
    )

方法2:改用ASGI模式运行Flask(推荐)

Flask 2.0及以上版本支持ASGI协议,搭配ASGI服务器(如Uvicorn)可以原生处理异步生成器,无需修改核心逻辑:

  1. 安装依赖:
pip install uvicorn flask
  1. 修改启动方式(假设你的Flask app文件名为app.py):
# app.py末尾添加
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=5000)
  1. 直接运行python app.py,此时Flask以ASGI模式运行,Werkzeug会用异步方式处理响应体,兼容异步生成器。

方法3:重写yield_file()为同步生成器

如果不需要异步特性,可以将原异步生成器改写成同步版本,直接使用普通yield语法生成数据,这样就能和Flask的同步WSGI环境兼容。


内容的提问来源于stack exchange,提问作者TechShreyash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 00:45:17