router.maxmultipartmemory仅限制内存缓存大小,不阻止大文件上传;超限时自动写入临时磁盘文件,gin仍可获取file对象;真正截断需在handler中主动校验并abort,且须同步配置nginx的client_max_body_size。

router.MaxMultipartMemory 只限制内存,不拦大文件
router.MaxMultipartMemory 设置的是 multipart 表单解析时允许使用的最大内存(单位字节),不是文件总大小的硬性闸门。当上传文件超过该值,net/http 会自动把超出部分写入临时磁盘文件(/tmp 或 os.TempDir()),Gin 仍能正常拿到 file 对象——所以你改了 router.MaxMultipartMemory = 1 却没报错,是预期行为,不是配置失效。
- 它只影响“内存中缓存多少”,不影响“最终能否收到文件”
- 真正被截断的场景:整个 multipart body(含所有字段+所有文件头)加起来超限,此时
c.MultipartForm()或c.FormFile()会直接 panic 或返回 error - 单个大文件(比如 500MB)即使设成
8(8MB),只要表单其余部分小,照样能传进来
真要拦住大文件,得在 handler 里手动校验
靠 Gin 自身无法实现“文件体积 > X MB 就拒绝”,必须自己读取并判断。最稳妥的方式是在调用 c.FormFile() 后,立刻用 file.Size 做阈值检查:
-
file.Size是准确的文件字节数,无需打开文件,开销极小 - 推荐阈值硬编码,比如
if file.Size > 100*1024*1024 { c.AbortWithStatusJSON(400, gin.H{"error": "file too large"}) } - 别依赖
c.Request.ContentLength:multipart 请求里它常为 -1,不可靠 - 多文件场景下,要遍历
form.File["xxx"]逐个检查,不能只看第一个
Nginx 层必须同步配 client_max_body_size
如果前端直连 Gin(无反向代理),那 Go 层校验就够了;但生产环境几乎都过 Nginx,此时 client_max_body_size 是第一道防线,且它触发更早、更干净:
- 未达 Nginx 限制 → 请求进 Gin → Go 层校验
- 超过 Nginx 限制 → 直接返回
413 Request Entity Too Large,Gin 根本收不到请求 - 必须写在匹配上传路径的
location块里,例如:location /upload { client_max_body_size 100M; } - 别忘了配套调大
client_body_timeout和client_body_buffer_size,否则大文件上传中途易超时或失败
临时文件残留和并发冲突容易被忽略
你以为拦住大文件就安全了?其实更隐蔽的风险在后面:
-
c.FormFile()返回的file对象底层可能已创建临时文件,即使你 abort 掉请求,这个文件不会自动清理 - 多个请求同时上传同名文件(比如都叫
avatar.jpg),c.SaveUploadedFile()会覆盖,没做重命名就是数据灾难 - 磁盘满时
os.Create()失败,错误没被defer捕获,日志里只剩空 panic - 没设
os.Chmod(dstPath, 0644),某些 Linux 环境下文件权限为 0600,后续服务读不了











