router.MaxMultipartMemory仅控制内存缓冲上限,不拦截总上传大小;必须在handler中显式校验file.Size才能真正限制文件体积,否则大文件仍可成功解析并进入业务逻辑。

router.MaxMultipartMemory 只控制内存缓冲区大小,不等于文件总大小限制。想真正拦住超大文件上传,必须手动校验 file.Size。
router.MaxMultipartMemory 是什么,为什么设了没用?
- 它只限制 multipart 解析时用于暂存表单字段和小文件的内存上限(单位是字节),默认 32 MiB(即
32 << 20)。 - 当上传文件超过该值,Gin 会自动把文件内容写入临时磁盘(
/tmp或系统指定目录),继续解析请求 —— 所以你设成1或8<<20,都不会让大文件直接报错或被拒绝。 - 它影响的是内存占用和解析行为,不是业务层面的“文件大小阈值”。
常见错误现象:
- 设了
router.MaxMultipartMemory = 8 << 20,但传个 500MB 的 zip 仍能进 handler - 日志里没报错,
c.FormFile成功返回,file.Size显示几百 MB
怎么在 handler 里做真正的大小限制?
必须在调用 c.FormFile 后、保存前,显式检查 file.Size:
file, err := c.FormFile("file")
if err != nil {
c.String(http.StatusBadRequest, "no file received")
return
}
if file.Size > 10<<20 { // 10 MiB
c.String(http.StatusBadRequest, "file too large: max 10 MiB")
return
}关键点:
-
file.Size是准确的文件字节数(Gin 已从 multipart 中解析出该元信息) - 检查必须放在
c.SaveUploadedFile或io.Copy之前,否则文件已开始写入 - 多文件场景下,要对每个
file单独判断,不能只看form.File["files"]长度
为什么不能只靠中间件或全局配置拦住大文件?
- Gin 没有内置「请求体总大小拦截」机制(不像某些框架提供
LimitRequestBody) - HTTP 层面无法在不解析 multipart boundary 的前提下知道文件大小 —— 它藏在 body 某段 Content-Disposition 后面
- 你没法在
c.Request.Body读取前就判断整体体积,除非自己实现流式 parser(不现实)
所以务实做法就是:
- 保持
router.MaxMultipartMemory合理(比如32 << 20),避免小文件全占内存 - 在业务 handler 中用
file.Size做第一道校验 - 如果还需更早拦截(如防 DOS),得配合反向代理(Nginx 的
client_max_body_size)或自定义http.Handler包裹 Gin 路由
容易被忽略的细节
-
file.Size对空文件或损坏 multipart 是可靠的,但前提是c.FormFile成功返回;如果前端字段名错、没传文件,err非 nil,file是零值,此时file.Size为 0,别误判 - 使用
c.MultipartForm()获取多文件时,每个form.File["key"][i]也是*multipart.FileHeader,同样有.Size字段 - 如果用
c.Request.FormFile(原生 net/http),也一样要检查header.Size,逻辑不变
真正起作用的永远是那一行:if file.Size > 10<<20。其他都是辅助或兜底。

















