应禁用Flask默认multipart解析,改用request.stream流式读取分块数据,配合upload_id唯一标识、Redis存元数据、按chunk_index排序合并,防止内存溢出与文件错乱。

Flask接收分片时如何避免内存溢出?
直接用 request.files 读取整个分片会把全部内容加载进内存,100MB分片就可能吃光服务进程内存。必须绕过 Flask 默认的文件解析流程,改用流式读取原始 body。
- 禁用 Flask 的 multipart 解析:启动时设
app.config['MAX_CONTENT_LENGTH'] = 0(或设为合理上限),并在路由上加@app.route(..., methods=['POST']),不依赖request.files - 用
request.stream.read(chunk_size)分块读取,chunk_size建议设为 8192 或 65536,避免小 chunk 频繁系统调用 - 务必校验
Content-Length头是否与实际读取字节数一致,防止客户端伪造长度导致后续逻辑错乱
如何用唯一标识关联分片与最终文件?
不能靠前端传来的文件名——重名、路径注入、编码混乱都会出问题。必须由服务端生成稳定、可索引的上传 ID,并绑定元数据。
- 推荐组合方式:
hashlib.sha256(f"{filename}_{timestamp}_{random_string}").hexdigest()[:16],存为upload_id - 每个分片请求必须携带该
upload_id(放在 URL path、query 或 header 中,别放 body 里——body 是纯二进制流) - 用 Redis 存元数据:
redis.hset(f"upload:{upload_id}", mapping={"filename": name, "total_size": total, "chunk_count": n}),避免每次查数据库
合并分片时为什么文件内容会错乱?
分片到达顺序不确定,直接按接收顺序写入会导致最终文件结构损坏。必须按分片序号(chunk_index)排序后拼接。
- 每个分片请求必须带
chunk_index(从 0 开始)和total_chunks,服务端验证范围:0 - 分片落地建议存为
/uploads/{upload_id}/{chunk_index},用整数命名,便于后续sorted(os.listdir(...))获取有序列表 - 合并时用
with open(final_path, 'wb') as f: for idx in range(total): f.write(open(f'{upload_id}/{idx}', 'rb').read())—— 不要一次性 load 所有 chunk 到内存
断点续传如何判断哪些分片已存在?
前端需要知道“我已经传了哪几片”,这不能靠服务端猜,必须提供明确的查询接口并返回确定状态。
- 暴露 GET 接口如
/api/upload/{upload_id}/status,返回 JSON:{"uploaded_chunks": [0, 2, 4], "total_chunks": 10} - 服务端查
os.listdir(f'/uploads/{upload_id}')并提取文件名转 int,过滤掉非数字文件;注意加 try/except 防止目录不存在或权限错误 - 前端根据返回结果跳过已传分片,但需重试机制:即使服务端说“已存在”,也应尝试 HEAD 请求确认文件大小是否匹配,防止写入中途中断导致残片
分片存储路径权限、磁盘空间监控、上传 ID 过期清理(比如 24 小时未完成就删)、以及并发上传时的 Redis 锁(防止同一 upload_id 被多个请求同时合并)——这些不是可选项,是上线前必须处理的边界。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











