上传后需先保存文件到唯一临时路径并确认 close() 成功,再压缩;parsemultipartform 必须显式调用且 maxmemory 设为 32,否则 r.formfile 返回 nil 或 panic。

上传后立刻压缩会失败,因为 r.FormFile 返回的句柄还没把完整内容写入磁盘;必须先保存到唯一临时路径并确认 Close() 成功,再启动压缩。
ParseMultipartForm 必须显式调用且设合理 maxMemory
漏掉这一步,r.FormFile 会返回 nil 或 panic;传 0 会让所有文件直写磁盘,失去内存缓冲优势。
-
maxMemory建议设为32 (32MB),覆盖多数图片场景 - 超过该阈值的文件自动落盘,但路径不可控 —— 所以仍需自己保存到明确位置
- 错误必须检查:
ParseMultipartForm失败可能因请求中断、字段名错、超限等
保存文件前必须做类型校验,不能信 filename 或 header.Size
客户端可随意伪造扩展名和 header.Size,真实类型得看文件头(magic bytes)。
- 用
http.DetectContentType或手动读前 512 字节比对 JPEG(FFD8FFE0)、PNG(89504E47)、GIF(47494638) - 白名单只允许
image/jpeg、image/png、image/gif - 保存时用
os.CreateTemp("", "upload-*.bin")生成唯一名,避免多文件冲突或覆盖
压缩逻辑要与文件保存解耦,失败必须清理残留
压缩中途 panic 或 error(如磁盘满、权限不足)会导致临时文件滞留,下次上传可能因同名冲突或占满 /tmp。
- 不要只靠
defer os.Remove—— 压缩前就出错时它不执行;panic 时也可能来不及运行 - 正确做法:保存成功后记录临时路径,压缩失败时显式
os.Remove并检查 error - 选压缩库要看场景:
archive/zip适合打包多图,但需全量加载;github.com/klauspost/compress/zstd支持流式压单图,内存稳定在 ~1MB,适合大图
图片缩放质量控制比尺寸控制更关键
单纯缩尺寸易导致模糊或细节丢失,优先调 JPEG 质量参数(1–100),再考虑降分辨率。
- 从质量 95 开始试,每步降 5,直到文件 ≤ 目标大小(如 200KB)
- 用
jpeg.Encode(dst, img, &jpeg.Options{Quality: q})控制输出质量 - 缩放时用
golang.org/x/image/draw.CatmullRom,但注意:必须新建image.RGBA目标图,不能复用原图矩形;PNG 透明通道要保留,否则背景变黑
最易被忽略的是:压缩不是独立步骤,它依赖保存动作的完整性 —— file.Close() 的 error 必须检查,否则底层 fd 可能未释放,临时文件锁住删不掉。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











