gin-contrib/gzip需配置阈值、排除路径与监控接口,避免小响应增开销、重复压缩及prometheus指标丢失;必须在路由注册前挂载,且生产推荐gzip.bestspeed。

Gin 或 net/http 中开启 Gzip 不等于“加一行代码就完事”,必须结合响应体大小、MIME 类型、状态码和前置代理情况做条件判断,否则容易白加头、压坏内容或浪费 CPU。
gin-contrib/gzip 中间件怎么配才不踩坑
直接用 gzip.Gzip(gzip.DefaultCompression) 会压缩所有匹配 MIME 的响应,但小响应(比如 200B 的 JSON)加上 gzip 头反而更大;已带 Content-Encoding: gzip 的响应(如上游 Nginx 已压过)再压一次会出错。
- 务必设置阈值:用
gzip.Gzip(gzip.DefaultCompression, gzip.WithMinSize(1024)),跳过小于 1KB 的响应 - 排除已压缩类型:PDF、ZIP、AVIF 等本身压缩率高,再 gzip 可能增体积,加
gzip.WithExcludedPathsRegexp("^/.*\.(pdf|zip|avif|webp)$") - 跳过监控接口:Prometheus 客户端不支持压缩响应,加
gzip.WithExcludedPaths([]string{"/health", "/metrics"}) - 别在
r.Static()之后挂载中间件——它对静态文件无效,必须在r.Use(...)且早于路由注册
net/http 原生 handler 怎么安全包装 gzip.Writer
自己写中间件比依赖第三方更可控,尤其要处理 WriteHeader 和 Write 的时序、避免多次 Close()、确保 Content-Encoding 和 Vary 头只设一次。
- 先检查
r.Header.Get("Accept-Encoding")是否含"gzip",不含就直传 - 创建
gzip.NewWriter(w)后,**首次 Write 前**必须调用w.Header().Set("Content-Encoding", "gzip")和w.Header().Set("Vary", "Accept-Encoding") - 重写
Write()方法时,若未写过 header,需先WriteHeader(http.StatusOK)再写压缩流 - 在
Write()或WriteHeader()返回前,**不能调用gzWriter.Close()**;应延迟到 handler 返回后,在自定义ResponseWriter的Flush()或CloseNotify()阶段关闭
为什么 gzip.BestSpeed 比 DefaultCompression 更适合 Web 响应
HTTP 响应是短时、高频、CPU 敏感场景,gzip.DefaultCompression(级别 6)在压缩率和速度间折中,但对 JSON/HTML 这类文本,级别 1(gzip.BestSpeed)压缩率只低 5%~8%,而 CPU 占用下降 40%+,TPS 提升明显。
- 级别 1 能覆盖大部分文本特征(重复 token、空格缩进、字段名),对 Go 的
json.Marshal()输出效果稳定 - 级别 9 在生产环境极少必要——它会让单次响应延迟从 2ms 拉到 15ms+,且并发高时容易拖垮 CPU
- 如果响应体确定大于 10KB(如报表 CSV),可对特定路由单独用
gzip.NewWriterLevel(buf, gzip.BestCompression),但不要全局启用
验证压缩是否真生效的三个硬指标
光看响应头有 Content-Encoding: gzip 没用,很多中间件只是加了头但没真正压缩内容,客户端解压失败或返回空白。
- 用
curl -H "Accept-Encoding: gzip" -I http://localhost:8080/api/data确认返回头含Content-Encoding: gzip和Vary: Accept-Encoding - 用
curl -H "Accept-Encoding: gzip" http://localhost:8080/api/data | gunzip -t测试能否无错解压(返回 0 才算成功) - 对比
Content-Length:纯文本接口压缩后应下降 ≥60%;若只降 5%~10%,大概率是 MIME 类型没匹配上(比如后端返回text/plain,但中间件默认只压text/html和application/json)
最易被忽略的是:gzip 中间件无法感知反向代理是否已压缩。如果你用 Nginx 做了 gzip on,Go 层再开 gzip 就是重复压缩,而错误往往表现为部分客户端解压失败、部分正常——这种非确定性问题最难定位。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











