
在 FastAPI 中使用 StreamingResponse 代理下游 HTTP 流时,若误用同步请求库(如 requests),会导致事件循环阻塞、流式响应失效。必须改用异步 HTTP 客户端(如 httpx.AsyncClient)并配合 async for 迭代响应体,才能实现真正的逐块转发。
在 fastapi 中使用 `streamingresponse` 代理下游 http 流时,若误用同步请求库(如 `requests`),会导致事件循环阻塞、流式响应失效。必须改用异步 http 客户端(如 `httpx.asyncclient`)并配合 `async for` 迭代响应体,才能实现真正的逐块转发。
FastAPI 基于异步运行时(如 Uvicorn),其流式响应能力高度依赖协程的非阻塞性。当你在 async def 函数中调用同步库 requests.post(..., stream=True),该调用会完全阻塞当前事件循环线程,直到整个响应体读取完毕——此时 yield 实际上是在同步上下文中批量执行,而非按需异步推送,因此前端收到的是“一次性完整响应”,而非实时流。
✅ 正确做法是全程保持异步:使用 httpx.AsyncClient 发起异步流式请求,并通过 response.aiter_bytes() 或 response.aiter_lines() 异步迭代响应数据块。以下为可直接运行的完整示例:
import httpx
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse
app = FastAPI()
# 模拟上游流式接口(返回 NDJSON)
@app.post("/stream-source")
async def stream_source():
async def result_generator():
for i, suffix in enumerate(["a", "ab", "abc", "abcd"]):
yield ({"Field": suffix}) # 注意:此处返回 dict,StreamingResponse 会自动序列化
await asyncio.sleep(0.5) # 模拟延迟生成
async def ndjson_stream():
async for item in result_generator():
yield json.dumps(item, ensure_ascii=False) + "\n"
return StreamingResponse(ndjson_stream(), media_type="application/x-ndjson")
# 流式代理接口:真正异步转发
@app.post("/test")
async def test_api(request: Request):
async def stream_results():
async with httpx.AsyncClient() as client:
# 注意:URL 需指向实际运行的上游服务(如本例中 /stream-source)
async with client.stream(
"POST",
"http://127.0.0.1:8000/stream-source",
json={},
timeout=30.0
) as response:
# 逐块异步读取,避免缓冲累积
async for chunk in response.aiter_bytes(chunk_size=1024):
yield chunk
return StreamingResponse(
stream_results(),
media_type="application/x-ndjson",
headers={"X-Content-Type-Options": "nosniff"} # 可选安全头
)⚠️ 关键注意事项:
-
禁止混用同步/异步 I/O:
requests是同步库,任何在其内部的for chunk in r.iter_content()都会阻塞事件循环,即使外层函数声明为async。 -
显式管理异步生命周期:务必使用
async with确保AsyncClient和响应对象被正确关闭,防止连接泄漏。 -
合理设置
chunk_size:过小(如 1)增加调度开销;过大(如None)可能退化为全量读取。推荐 1024–8192 字节区间。 -
错误传播与超时:建议为
client.stream()显式指定timeout,并在外层捕获httpx.HTTPStatusError或httpx.RequestError,避免未处理异常中断流。 -
NDJSON 兼容性:确保上下游
media_type统一为application/x-ndjson,且每行严格为一个合法 JSON 对象 +\n换行符。
通过以上实现,客户端发起 /test 请求后,将实时接收到与上游 /stream-source 完全一致的逐行流式响应,真正实现低延迟、高吞吐的流式代理。


















