flask 中 request.files 不能直接处理 gb 级文件,因其默认将整个文件读入内存或临时磁盘,易触发内存溢出或超时;应改用 request.stream 分块读取并边读边存,配合禁用自动解析、合理设置中间件超时与大小限制。

Flask 中 request.files 为什么不能直接处理 GB 级文件?
因为默认 Flask 将整个上传文件读入内存(或临时磁盘),request.files 返回的是 FileStorage 对象,底层调用 read() 时会一次性加载全部内容。GB 文件触发内存溢出或超时,常见报错如 werkzeug.exceptions.RequestEntityTooLarge 或进程被 OOM killer 杀掉。
真正可行的路径是绕过 request.files,直接从 request.stream 读取原始字节流,并配合 stream=True 和分块写入。关键前提是禁用 Flask 的自动解析:
- 设置
app.config['MAX_CONTENT_LENGTH'] = None(或设为足够大,但不推荐) - 在路由函数开头加
request.get_data(parse_form=False, cache=False)防止 Werkzeug 提前消费 stream - 后续所有读取必须用
request.stream.read(chunk_size),且 chunk_size 建议 ≤ 8192 字节
如何用 request.stream 实现安全的大文件上传?
核心是“边读边存”,避免内存堆积。不要调用 request.files,也不要依赖 form 解析 multipart boundary —— 直接按 HTTP body 原始流处理。
实操要点:
- 路由必须用
methods=['POST'],且前端Content-Type设为multipart/form-data(boundary 由浏览器自动生成,Flask 不解析它才安全) - 用
for chunk in iter(lambda: request.stream.read(8192), b''):循环读取,每次只占 8KB 内存 - 写入目标文件时用
open(..., 'ab')追加模式,避免覆盖或 seek 错误 - 务必校验
Content-Length头是否合理(如 >100GB 可直接拒收),防止恶意请求耗尽磁盘 - 示例片段:
with open('/path/to/file.bin', 'ab') as f: while True: chunk = request.stream.read(8192) if not chunk: break f.write(chunk)
下载大文件时为什么不能用 send_file()?
send_file() 默认会把整个文件读进内存再发出去,GB 文件同样导致内存爆炸。正确做法是返回一个可迭代的生成器,并设置 Response 的 direct_passthrough=True。
关键控制点:
- 用
open(..., 'rb')以二进制流打开,配合yield分块返回:yield from iter(lambda: f.read(65536), b'') - 必须手动设置
Content-Length(通过os.path.getsize())和Content-Type(如application/octet-stream) - 禁用 Flask 自动 gzip 压缩(大文件压缩反而拖慢,且可能破坏二进制完整性),设置
response.headers['Content-Encoding'] = 'identity' - 若需断点续传,必须实现
Range请求解析,仅返回对应 byte range —— 这部分逻辑无法靠send_file()自动完成
生产环境必须注意的三个隐藏陷阱
本地跑通不等于线上可用。Nginx、uWSGI/Gunicorn、浏览器都可能截断或重置连接。
容易忽略的细节:
- Nginx 默认
client_max_body_size 1m,必须显式设为0(无限制)或足够值,并调大client_body_timeout和proxy_read_timeout - Gunicorn 的
--timeout默认 30 秒,大文件上传/下载必须设为 ≥ 预估最大耗时(如--timeout 3600) - Chrome 对长时间无响应的 POST 请求会静默终止,建议前端用
XMLHttpRequest或fetch并监听upload.onprogress,后端返回简单 JSON 状态码而非 HTML 页面
流式传输的边界很薄:一端配置漏掉,整条链路就断。每个中间件都要单独验证 timeout 和 buffer 行为,不能只看 Python 层代码。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











