适用于Gin和net/http的 gzip 中间件。基于 Content-Type
、Content-Length
、扩展名等要素自动判断是否启用压缩。
import github.com/nanmu42/gzip
func main() {
g := gin.Default()
// 使用默认设定
g.Use(gzip.DefaultHandler().Gin)
g.GET("/", func(c *gin.Context) {
c.JSON( http.StatusOK, map[string]interface{}{
"code": 0,
"msg": "hello",
"data": fmt.Sprintf("l%sng!", strings.Repeat("o", 1000)),
})
})
log.Println(g.Run(fmt.Sprintf(":%d", 3000)))
}
import github.com/nanmu42/gzip
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
writeString(w, fmt.Sprintf("This content is compressed: l%sng!", strings.Repeat("o", 1000)))
})
// 使用默认设定
log.Println( http.ListenAndServe(fmt.Sprintf(":%d", 3001), gzip.DefaultHandler().WrapHandler(mux)))
}
func writeString(w http.ResponseWriter, payload string) {
w.Header().Set("Content-Type", "text/plain; charset=utf8")
_, _ = io.WriteString(w, payload+"\n")
}
Handler
在创建Handler
时,可以定制参数以满足你的需要:
import github.com/nanmu42/gzip
handler := gzip.NewHandler(gzip.Config{
// gzip 压缩等级
CompressionLevel: 6,
// 使用 gzip 的最小 body 体积,单位:byte
MinContentLength: 256,
// 请求过滤器基于请求来判断是否对这条请求的返回启用 gzip,
// 过滤器按其定义顺序执行,下同。
RequestFilter: []RequestFilter{
NewCommonRequestFilter(),
DefaultExtensionFilter(),
},
// 返回 header 过滤器基于返回的 header 判断是否对这条请求的返回启用 gzip
ResponseHeaderFilter: []ResponseHeaderFilter{
NewSkipCompressedFilter(),
DefaultContentTypeFilter(),
},
})
RequestFilter
和 ResponseHeaderFilter
是 interface.
你可以实现你自己的过滤器。
Content-Type
,Handler 不会对未知Content-Type
的返回进行类型猜测;Content-Length
中查询 body 体积,如果没有就再查看http.ResponseWriter.Write(data []byte)
在首次调用时的 len(data)
作为参考。倘若返回的 Content-Length
不存在,且http.ResponseWriter.Write(data []byte)
首次调用时的len(data)
较小,这条返回会被错误认为无需压缩。如果你使用的是 Gin 的c.JSON()
或c.PureJSON()
,无需担心上述问题。
如果你直接使用net/http
,请妥善处理上述问题。
1
missdeer 2019-12-11 08:47:53 +08:00
让前置 nginx 处理如何?
|
2
nanmu42 OP @missdeer 当返回的 JSON 大于 2KB 时,Golang 会使用 chunk 的形式传输,这个时候没有`Content-Length`,Nginx 的 `ngx_http_gzip_module` 的 `gzip_min_length` 仅从 `Content-Length` 判断是否压缩,导致内容不被压缩。
|