Compress中间件需手动引入并显式配置,否则因MIME类型不匹配、MinSize阈值未达、Content-Length缺失或路由顺序错误而失效;正确做法是用compress.New()指定MimeTypes、Level和MinSize,并避免对已压缩二进制文件启用。

Compress 中间件在 Fiber 框架中不是内置组件,它来自第三方库 fiber/compress(即 github.com/gofiber/compress),需手动引入并注册。默认不启用、不自动匹配 MIME 类型、不处理流式响应——直接加中间件往往压不出效果。
为什么 Compress 中间件没生效?
常见现象是:接口返回 JSON,Accept-Encoding: gzip 头也带了,但响应头里没有 Content-Encoding: gzip,Body 也没变小。
- 未显式调用
compress.New()配置,而是用了空构造(compress.New()默认只压缩 ≥ 1KB 的text/*和application/json,但部分版本对application/json匹配不严谨) - 路由注册顺序错误:把
compress.New()放在了app.Get(...)之后,或被其他中间件(如logger)拦截了写入流 - 响应体由
c.SendString()或c.JSON()发出,但未设置Content-Length,而compress依赖底层ResponseWriter能判断响应大小——流式发送(chunked)时长度未知,压缩器会跳过 - Fiber v2.48+ 默认禁用
Content-Length自动计算;若你用的是c.Status(200).JSON(data),它内部走的是流式序列化,不会写Content-Length
怎么正确配置 compress.New()?
必须显式传参控制 MIME 类型和阈值,尤其当你的 API 返回 application/vnd.api+json 或 application/geo+json 这类子类型时,默认列表不覆盖。
- 使用
compress.Config显式声明MimeTypes,至少包含:"application/json"、"text/html"、"text/plain" -
Level推荐设为compress.LevelBestSpeed(值 1)或compress.LevelDefault(值 6),避免高阶压缩拖慢高并发响应 -
MinSize建议设为1024(1KB),太小(如 100)会导致小响应徒增 CPU 开销
import "github.com/gofiber/compress"
app.Use(compress.New(compress.Config{
Level: compress.LevelDefault,
MinSize: 1024,
MimeTypes: []string{
"application/json",
"text/html",
"text/plain",
"text/css",
"application/javascript",
},
}))
如何确保 JSON 响应一定被压缩?
根本问题是:Fiber 的 c.JSON() 不写 Content-Length,而 compress 中间件依赖该头做大小预判。绕过方式只有两个:
- 改用
c.Status(200).Send([]byte(jsonStr)),自己序列化 + 手动设长:c.Response().Header.Set("Content-Length", strconv.Itoa(len(jsonBytes))) - 或统一用
ResponseWriter底层写入:c.Context().Response.BodyWriter()获取原始 writer,先写再 flush(较侵入) - 更稳妥的做法:在中间件后加一层包装,用
app.Use(func(c *fiber.Ctx) error { ... })拦截JSON调用,提前估算长度(例如用json.Marshal(data)一次,缓存结果并写长)——适合 QPS 不高的管理接口
压缩二进制文件(如 PNG、PDF)会适得其反
不要把 image/*、application/pdf、application/zip 加进 MimeTypes 列表。Gzip 对已压缩格式无效,反而可能增大体积 0.1%~0.5%,且白耗 CPU。
- 若某路由明确返回图片:
app.Get("/avatar/:id", func(c *fiber.Ctx) error { return c.SendFile("...") }),应在该路由前加c.Set("Content-Encoding", "")清除压缩标记,或用app.Get("/avatar/:id", compress.New(...), func(c *fiber.Ctx) error {...})把 compress 局部禁用 - 更推荐做法:全局 compress 启用,但对特定路径用
app.Use("/files/*", func(c *fiber.Ctx) error { c.Next() })跳过中间件
compress 看似开箱即用,实际生效强依赖响应头完整性与 MIME 类型显式声明。最容易被忽略的点是:它不修 Content-Length,也不感知你用的是 c.JSON 还是 c.SendString——压缩与否,最终由底层 HTTP 写入时机决定。


















