直接用http.post传大文件会失败,因客户端内存溢出、服务端oom或超时,常见错误包括eof、读写超时及nginx 413错误;需分片上传并严格对齐x-upload-id、content-range和upload-number参数,服务端须流式接收、校验、暂存并安全合并。

为什么直接用 http.Post 传大文件会失败
因为默认 HTTP 客户端没有流式上传支持,内存会爆;服务端(比如标准 net/http)读取 request.Body 时若不设限,也会 OOM 或超时。常见错误是看到 EOF、io: read/write timeout 或 Nginx 返回 413 Request Entity Too Large。
- 客户端必须分块读取文件,用
multipart.Writer拼接每段,避免全量加载到内存 - 服务端需禁用默认的
MaxBytesReader限制(它会提前截断大 Body),改用自定义流式解析 - 务必在请求头里带
Content-Range和唯一X-Upload-ID,否则无法定位分片位置
前端怎么发分片?关键参数和后端怎么对齐
前端不是随便切几段 POST 就行——服务端需要能还原原始顺序和偏移。核心是三个字段必须严格一致:
-
X-Upload-ID:UUID,整个上传生命周期唯一,前端生成后所有分片共用 -
Content-Range:格式为bytes 0-999999/10485760,其中末尾是总大小(非当前分片大小),服务端靠它校验完整性 -
Upload-Number(或类似自定义 header):整数序号,从 1 开始,不能跳号或重复
示例请求片段(curl):
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
curl -X POST http://localhost:8080/upload/chunk \ -H "X-Upload-ID: a1b2c3d4" \ -H "Content-Range: bytes 0-1048575/10485760" \ -H "Upload-Number: 1" \ -F "file=@part1.bin"
服务端如何安全接收并暂存分片
不能把每个分片直接写进同一目录下同名文件——并发写会冲突,且没校验机制。推荐方案是按 X-Upload-ID 建临时目录,每个分片存为 chunk_1、chunk_2 等,并附带 SHA256 校验值(前端可算好传过来,服务端比对)。
- 用
os.OpenFile配合os.O_CREATE | os.O_WRONLY | os.O_EXCL防止覆盖已有分片 - 接收完立即
f.Sync(),避免断电丢数据;但别每写 1KB 就 Sync,性能差 - 分片文件权限设为
0600,防止未合并前被意外读取 - 设置上传超时:单个分片超过 10 分钟没续传,自动清理该
X-Upload-ID下全部临时文件
合并时为什么不能简单 cat chunk_* > final
因为分片顺序依赖 Upload-Number,不是文件名字典序;而且要防篡改、防缺失、防重复。必须先读取所有已上传分片元信息(路径 + 大小 + SHA256),按序号排序,再逐个 io.Copy 到目标文件。
- 检查总数是否等于
Content-Range中声明的总长度,不等则拒绝合并 - 合并前用
os.Rename把临时目录整体移到归档区(如/uploads/complete/a1b2c3d4),避免中间态暴露 - 合并过程加锁(用
sync.Mutex或 Redis 分布式锁),防止同一X-Upload-ID被多次触发 - 成功后清空临时目录,但保留日志:记录起始时间、分片数、总耗时、最终 SHA256
最易忽略的是:没校验分片之间是否有重叠或空洞——比如收到 chunk_1(0–999)和 chunk_3(2000–2999),中间缺了 1000–1999,这种必须报错,不能静默跳过。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










