Go标准库原生支持HTTP响应gzip压缩,需检测Accept-Encoding头、设置Content-Encoding和Vary头,跳过小响应、已压缩文件及204/304状态码,并避免压缩含Set-Cookie的响应。

Go 标准库原生支持 HTTP 响应的 gzip 压缩,无需第三方依赖。关键在于正确配置 http.ResponseWriter,并结合中间件统一处理,避免手动重复编码。
启用 gzip 压缩的基本方式
Go 1.8+ 提供了 gzip.NewWriter 和标准 http.ResponseWriter 的兼容封装。最直接的做法是:在 handler 中检测请求头 Accept-Encoding: gzip,若匹配则包装响应体为 gzip writer,并设置响应头 Content-Encoding: gzip 和 Vary: Accept-Encoding(告知缓存代理该响应依赖于请求头)。
使用官方 net/http/httputil 中间件(推荐)
Go 官方未内置 gzip 中间件,但社区广泛采用 github.com/gorilla/handlers.CompressHandler 或更轻量的 net/http/pprof 风格封装。不过从 Go 1.22 起,net/http 新增了 http.Handler 接口的增强能力,更推荐自己写一个简洁中间件:
- 检查
r.Header.Get("Accept-Encoding")是否包含gzip - 若支持,创建
gzip.NewWriter(w),并返回自定义responseWriter类型,重写Write、WriteHeader和Header() - 务必在
WriteHeader后或首次Write前设置Content-Encoding和Vary头 - 调用
gzWriter.Close()确保数据刷出,且不能多次关闭
避免常见陷阱
压缩不是万能的,需注意边界情况:
立即学习“go语言免费学习笔记(深入)”;
- 不压缩小响应:小于 ~150 字节的响应压缩后可能更大,建议跳过(可加长度判断)
- 跳过已压缩内容:如图片(.png/.jpg)、视频、PDF 等二进制文件,本身已压缩,再 gzip 可能无效甚至膨胀
- 禁止压缩含 Set-Cookie 的响应:某些旧版代理对压缩后的 Cookie 处理异常,虽非强制,但建议对含敏感头的响应禁用压缩
- 不要压缩 204/304 响应:这些状态码本就不含响应体,压缩无意义,还可能引发 header 冲突
完整中间件示例(无依赖)
以下是一个生产可用的轻量中间件(约 30 行),支持自动降级、长度阈值和安全头过滤:
func gzipMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
next.ServeHTTP(w, r)
return
}
w.Header().Set("Vary", "Accept-Encoding")
gz := gzip.NewWriter(w)
defer gz.Close()
w = &gzipResponseWriter{Writer: gz, ResponseWriter: w}
next.ServeHTTP(w, r)
})
}
type gzipResponseWriter struct {
io.Writer
http.ResponseWriter
}
func (w *gzipResponseWriter) Write(b []byte) (int, error) {
if w.Header().Get("Content-Encoding") == "" {
w.Header().Set("Content-Encoding", "gzip")
}
return w.Writer.Write(b)
}
func (w *gzipResponseWriter) WriteHeader(statusCode int) {
if statusCode < 300 && statusCode != 204 && statusCode != 304 {
w.Header().Set("Content-Encoding", "gzip")
}
w.ResponseWriter.WriteHeader(statusCode)
}
使用时只需:http.ListenAndServe(":8080", gzipMiddleware(yourRouter))。
基本上就这些。核心是“检测 + 包装 + 设置头 + 正确关闭”,不复杂但容易忽略细节。










