适用于 Gin 和 net/http 的 gzip 中间件,基于 Content-Type、Content-Length、扩展名等要素自动判断是否启用压缩

2019-12-10 18:36:25 +08:00
 nanmu42

gzip 中间件

项目地址: https://github.com/nanmu42/gzip

适用于Ginnet/http的 gzip 中间件。基于 Content-TypeContent-Length、扩展名等要素自动判断是否启用压缩。

使用示例

Gin

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)))
}

net/http

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(),
	},
})

RequestFilterResponseHeaderFilter 是 interface. 你可以实现你自己的过滤器。

Handler 的局限性

如果你使用的是 Gin 的c.JSON()c.PureJSON(),无需担心上述问题。

如果你直接使用net/http,请妥善处理上述问题。

2758 次点击
所在节点    分享创造
2 条回复
missdeer
2019-12-11 08:47:53 +08:00
让前置 nginx 处理如何?
nanmu42
2019-12-11 10:26:46 +08:00
@missdeer 当返回的 JSON 大于 2KB 时,Golang 会使用 chunk 的形式传输,这个时候没有`Content-Length`,Nginx 的 `ngx_http_gzip_module` 的 `gzip_min_length` 仅从 `Content-Length` 判断是否压缩,导致内容不被压缩。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/627727

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX