go http服务默认不压缩响应,需手动启用gzip或使用gorilla/handlers.compresshandler;注意仅压缩2xx响应、设置content-encoding头、避免与流式响应冲突。

Go HTTP 服务默认不压缩响应,需手动启用
Go 的 net/http 包本身不自动压缩响应体(比如 gzip、zstd),即使客户端发来 Accept-Encoding: gzip 请求头,http.ServeMux 和 http.Handler 默认也原样返回未压缩内容。这不是 bug,而是设计取舍:压缩涉及 CPU 开销、缓冲管理、Header 设置和流式写入控制,Go 选择交由上层决定是否启用、用哪种算法、压缩哪些内容类型。
用 gzip.Writer 手动包装 http.ResponseWriter
最轻量、可控性最强的方式是自己封装一个支持 gzip 的 ResponseWriter。关键点在于:检查请求头、设置 Content-Encoding、替换写入逻辑、避免多次压缩(比如后端已返回压缩数据)。
常见错误现象包括:gzip: invalid header(因重复 gzip)、响应体乱码(没改 Content-Encoding)、或 http: response.WriteHeader called multiple times(在包装器中误调 WriteHeader)。
- 只对状态码为 2xx 的响应压缩;304、204 等无 body 响应跳过
- 检查
r.Header.Get("Accept-Encoding")是否含gzip,且未被中间件提前消费 - 用
gzip.NewWriter(w)包装原始ResponseWriter,并在Write后调Close()刷新缓冲 - 务必在
WriteHeader前设置w.Header().Set("Content-Encoding", "gzip"),否则浏览器不解压
使用 github.com/gorilla/handlers.CompressHandler 快速集成
如果你不想手写压缩逻辑,gorilla/handlers 提供了开箱即用的中间件 CompressHandler,它支持 gzip 和 zstd(v1.5+),并自动处理 Vary: Accept-Encoding、缓存兼容性和边缘 case。
注意参数差异:CompressHandler 默认只压缩 text/*、application/json、application/javascript 等 MIME 类型,不压缩图片或二进制文件——这是合理默认,但若你返回自定义的 application/octet-stream 且希望压缩,需显式传入 handlers.CompressLevel(6) 并自定义 MIME 白名单。
性能影响方面:gzip 压缩在 CPU 上有可测开销(尤其高并发小响应),但通常远小于网络传输节省。建议在反向代理(如 Nginx)前启用,避免重复压缩。
压缩与 streaming response(如 text/event-stream)不兼容
HTTP 流式响应(SSE、长轮询 chunked transfer)不能直接套用 gzip.Writer,因为 gzip 需要完整输入或显式 flush,而流式写入要求低延迟分块输出。强行压缩会导致延迟激增或连接中断。
解决方式只有两个:
- 对流式接口禁用压缩(检查
r.Header.Get("Accept-Encoding")并跳过包装) - 改用
zstd(通过github.com/klauspost/compress/zstd)配合Encoder.WithEncoderLevel(zstd.EncoderLow),它比 gzip 更适合短块、低延迟场景,但仍需谨慎测试
最容易被忽略的是:某些 API 文档声称“支持 gzip”,但实际返回 SSE 时悄悄关闭了压缩——客户端却仍尝试解压,结果卡死或报错 unexpected EOF。务必在调试时用 curl -H "Accept-Encoding: gzip" -v http://localhost/endpoint 实际抓包确认响应头和 body 是否匹配。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











