必须用 http.maxbytesreader 在解析前硬性截断请求体,这是第一道防线;再用 fileheader.size 做业务级单文件校验;parsemultipartform 的 maxmemory 参数仅控制内存缓存上限,不替代总大小限制。

Go 文件上传的大小限制不能只靠 FileHeader.Size 或前端传来的字段,必须在请求体读取最上游就硬性截断,否则大文件可能已耗尽内存或带宽。
用 http.MaxBytesReader 在解析前拦截整个请求体
这是第一道、也是最关键的防线。它包装 r.Body,在底层 Read 调用时实时计数,超限时立即停止读取并关闭连接:
- 必须在任何解析操作(
r.FormFile、r.ParseMultipartForm、r.ParseForm)之前设置,否则无效 - 限制的是整个请求体字节数(含所有表单字段 + 所有文件),若允许多文件上传,需预留余量(例如单文件上限 10MB × 1.5 = 15MB)
- 触发后 handler 会收到
http.ErrBodyReadAfterClose或类似错误,客户端通常看到 400 或连接重置 - 示例:
http.MaxBytesReader(w, r.Body, 15*1024*1024)
用 FileHeader.Size 做业务级单文件校验
FileHeader.Size 是 multipart boundary 解析后得到的声明大小,不触发实际读取,可安全用于快速过滤:
- 它可被客户端伪造,因此必须与
MaxBytesReader配合使用才有意义 - 适合做二次校验:比如允许最大 10MB 图片,先用
MaxBytesReader限 15MB 总请求体,再用header.Size 精确判断 - 不要用
len(fileBytes)校验——大文件根本不能全读进内存 - 多文件场景下,在遍历
r.MultipartForm.File["files"]时逐个检查
用 io.LimitReader 控制单个文件流读取上限
当需要进一步控制单文件处理行为(如图片解码、魔数检测)时,应在打开文件后立刻包装:
-
mpf, header, _ := r.FormFile("file")返回的mpf是io.Reader,可直接传给io.LimitReader(mpf, maxSize) - 后续任何读取超过
maxSize都会静默返回io.EOF,避免解码器或校验逻辑陷入长耗时读取 - 特别适合图像校验:配合
image.Decode时,它只读必要头部,不会试图加载整张图 - 注意:此时
mpf已被包装,保存文件需重新调用r.FormFile或改用r.MultipartReader()流式处理
为什么 r.ParseMultipartForm(32 不是大小限制手段
这个调用只控制服务端“最多用多少内存缓存 multipart 数据”,不是上传限制开关:
- 设为
32 (32MB)表示 ≤32MB 的部分放内存,超的部分自动写磁盘——但客户端仍可发 2GB 文件,服务端照单全收 - 它不阻止网络传输,也不中断连接,仅影响存储策略
- 若不配合
MaxBytesReader,攻击者可轻松绕过,填满磁盘或拖垮 I/O - 真正起限流作用的是
MaxBytesReader,ParseMultipartForm只是辅助内存管理
最容易被忽略的一点:MaxBytesReader 必须在 handler 开头就设置,且不能被任何中间件或逻辑提前消费 r.Body;一旦 r.Body 被读过哪怕一个字节,再包就晚了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











