
在构建 web 服务时,文件下载是一个常见需求。然而,当文件体积较大时,不当的处理方式可能导致服务器内存耗尽,尤其是在高并发场景下。fastapi 提供多种响应类型,理解它们的适用场景对于优化性能至关重要。
许多开发者在尝试使用 StreamingResponse 返回文件时,可能会遇到内存溢出(Out Of Memory, OOM)的问题。一个常见的错误模式是,在将文件内容传递给 StreamingResponse 之前,使用 file.read() 方法一次性读取整个文件到内存中,如下所示:
import io
from fastapi import FastAPI
from starlette.responses import StreamingResponse
app = FastAPI()
@app.get("/download-large-file-problematic")
async def download_large_file_problematic():
filename = "path/to/your/large_file.zip" # 假设这是一个非常大的文件
try:
# ⚠️ 严重问题:file.read() 会一次性加载整个文件到内存
with open(filename, "rb") as f:
file_content = f.read()
headers = {'Content-Disposition': f'attachment; filename="{filename.split("/")[-1]}"'}
# io.BytesIO(file_content) 同样需要整个文件内容在内存中
return StreamingResponse(
content=io.BytesIO(file_content),
media_type="application/octet-stream",
headers=headers
)
except FileNotFoundError:
return {"message": "File not found"}尽管在 open() 函数中使用了 buffering 参数,但 io.BytesIO(file.read()) 这一操作本身就意味着整个文件的内容首先被 file.read() 加载到内存,然后再封装成 BytesIO 对象。对于 GB 级别的大文件,这会迅速耗尽服务器的可用内存,导致服务崩溃。
FastAPI (实际上是其底层 Starlette) 提供了一个专门用于文件传输的响应类:FileResponse。FileResponse 的设计初衷就是为了高效地处理本地文件传输,它直接接收文件路径作为参数,并负责以流式方式(分块)读取和发送文件内容,而无需将整个文件加载到内存中。这极大地优化了内存使用和传输效率。
以下是使用 FileResponse 解决大文件下载问题的正确方法:
from fastapi import FastAPI
from starlette.responses import FileResponse
import os
app = FastAPI()
# 假设你的项目根目录下有一个名为 'static' 的文件夹,其中包含 large_file.zip
# 为了演示,我们先创建一个虚拟的大文件
# import os
# with open("static/large_file.zip", "wb") as f:
# f.seek(1024 * 1024 * 100 - 1) # 100 MB
# f.write(b'\0')
@app.get("/download-large-file-optimized")
async def download_large_file_optimized():
file_path = "static/large_file.zip" # 替换为你的实际文件路径
if not os.path.exists(file_path):
return {"message": "File not found"}, 404
# FileResponse 直接接收文件路径
# 它会负责以流式方式读取和发送文件,无需一次性加载到内存
return FileResponse(
path=file_path,
media_type="application/zip", # 根据文件类型设置正确的 media_type
filename="my_large_file.zip", # 提供给用户下载的文件名
headers={"Content-Disposition": f"attachment; filename=my_large_file.zip"}
)
FileResponse 的优势与特点:
尽管 FileResponse 是处理本地大文件的首选,但 StreamingResponse 并非毫无用处。它适用于以下场景:
在这种情况下,StreamingResponse 接收一个可迭代对象(通常是生成器),每次迭代返回一个数据块,从而实现流式传输。
在 FastAPI 中处理文件下载时,选择正确的响应类型至关重要。
通过遵循这些最佳实践,你的 FastAPI 应用将能够更稳定、高效地处理大文件下载任务,提供更优质的用户体验。
以上就是FastAPI 大文件高效传输:使用 FileResponse 避免内存溢出的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号