FastAPI转发流式响应时yield无法实时输出内容的问题排查
FastAPI转发流式响应时yield无法实时输出内容的问题排查
兄弟,你这个问题的核心原因其实很明确:你在异步函数里用了同步的requests库,它会阻塞FastAPI的事件循环,导致你的yield没法实时输出内容,必须等整个请求完成后才会一次性返回所有结果。
咱们来拆解一下:
requests.post(..., stream=True)虽然开启了流模式,但它本身是同步IO操作。在FastAPI的异步上下文里,同步IO会卡住整个事件循环,没法及时把拿到的chunk通过yield发出去,只能等整个响应流全部接收完,才会继续执行后续的yield逻辑。- 而你看到
print(chunk)能实时输出,是因为同步的iter_content确实在逐步拿到数据,但事件循环被阻塞了,FastAPI没法及时把这些yield的chunk推送给客户端。
那怎么解决呢?换成异步HTTP客户端就好了,比如用aiohttp,它是完全异步的,不会阻塞事件循环。修改后的代码大概是这样:
import aiohttp from fastapi import FastAPI, Request from fastapi.responses import StreamingResponse @app.post('/test') async def test_api(request: Request): async def stream_results(): # 用aiohttp的异步会话 async with aiohttp.ClientSession() as session: async with session.post("http://127.0.0.1:8000/test_api", json={}) as r: # 异步迭代响应内容的chunk async for chunk in r.content.iter_chunked(1000): print(chunk) yield chunk return StreamingResponse(stream_results(), media_type='application/x-ndjson')
这样修改后,async for会实时拿到每个chunk就立刻yield出去,FastAPI的事件循环也不会被阻塞,客户端就能逐步收到流式响应了。
另外还要注意两个小细节:
- 确保原始的
/test_api端点返回的StreamingResponse没有被中间件缓存,FastAPI默认的中间件一般不会,但如果有自定义中间件的话要检查是否有缓存逻辑。 aiohttp的iter_chunked参数可以根据你的需求调整大小,和之前的1000保持一致就没问题。
备注:内容来源于stack exchange,提问作者John Brown
相关产品推荐
相关产品推荐

