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

FastAPI使用StreamingResponse返回大文件内存溢出,如何流式输出?

FastAPI大文件流式返回解决方案

你的问题核心在于当前代码里的file.read()会一次性将整个文件加载到内存,哪怕设置了buffering参数也没用——因为不带参数的read()默认读取文件全部内容。而StreamingResponse需要的是一个可迭代/异步可迭代对象来逐块输出数据,而非一次性的字节流。

下面提供两种可行的实现方式:

1. 同步流式返回(适合常规场景)

通过生成器函数逐块读取文件,避免全量加载:

from starlette.responses import StreamingResponse

def file_generator(file_path, chunk_size=1024*1024):  # 按1MB分块,可按需调整
    with open(file_path, "rb") as f:
        while chunk := f.read(chunk_size):
            yield chunk

# 接口中的返回逻辑
filename = "your_large_file.ext"
headers = {'Content-Disposition': f'attachment; filename="{filename}"'}
return StreamingResponse(
    content=file_generator(filename),
    media_type="application/octet-stream",
    headers=headers
)
  • 用with语句自动管理文件句柄,避免资源泄漏;
  • 生成器每次返回一块数据,StreamingResponse会逐块发送给客户端,内存仅保留当前块的大小。

2. 异步流式返回(与上传逻辑统一,适合高并发)

如果你的服务以异步为主,用aiofiles配合异步生成器实现全异步流式返回:

import aiofiles
from starlette.responses import StreamingResponse

async def async_file_generator(file_path, chunk_size=1024*1024):
    async with aiofiles.open(file_path, "rb") as f:
        while chunk := await f.read(chunk_size):
            yield chunk

# 接口中的返回逻辑
filename = "your_large_file.ext"
headers = {'Content-Disposition': f'attachment; filename="{filename}"'}
return StreamingResponse(
    content=async_file_generator(filename),
    media_type="application/octet-stream",
    headers=headers
)
  • 全程异步IO,不会阻塞FastAPI的事件循环,更适合高并发场景;
  • 同样逐块读取返回,彻底避免内存溢出问题。

额外注意事项

  • 务必避免使用无参数的file.read(),这是导致内存溢出的根本原因;
  • Content-Disposition的格式要正确,文件名需用双引号包裹,避免浏览器解析异常;
  • chunk_size可根据服务器内存和网络情况调整,常见取值为1MB~16MB。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 20:22:17