V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
nanmu42
V2EX  ›  Go 编程语言

发布 1.0.0 版本:用于 Gin 和 net/http 的 gzip 中间件,再也不担心返回的 JSON 太大了

  •  1
     
  •   nanmu42 ·
    nanmu42 · 2020-04-26 10:54:34 +08:00 · 3871 次点击
    这是一个创建于 1668 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Golang Gzip Middleware

    一个适用于Ginnet/http的 gzip 中间件,可直接用也可定制参数和过滤器,gzip 压缩你的返回。

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

    p.s.

    gzip 一般可以将文本返回(例如 JSON )压缩到 30%~70%.

    有的人喜欢在反向代理上做压缩,有的人喜欢在程序里就压缩,萝卜青菜各有所爱。:)

    第 1 条附言  ·  2020-04-27 09:35:36 +08:00
    gzip 压缩本身只是调用官方库,不难。要考虑的主演是另外的问题:
    客户端支持解压缩吗?(不支持就不能压缩)
    哪些内容类型需要压缩?判断基于 MIME 还是扩展名?(都要判断)
    数据流是不是已经压缩过?(看 header )
    返回最少要多大才值得压缩?(返回太小,压缩后更大,得不偿失)
    使用哪一个 gzip 级别?( cloudflare 做了一堆实验,nginx 直接取 1,这个问题偏玄学)
    流式传输的返回该如何判断返回大小?( buffer,没别的办法,content-length 这时不存在)

    主要是脏活累活,细节问题,性能问题( GC 要友好)。

    gin-contrib 只是看上去好,它 issue 里的问题其实就是上面这些点的体现,关键是官方并不怎么上心……
    23 条回复    2020-04-30 02:38:32 +08:00
    airplayxcom
        1
    airplayxcom  
       2020-04-26 11:41:15 +08:00   ❤️ 1
    已 star
    qwerthhusn
        2
    qwerthhusn  
       2020-04-26 11:49:13 +08:00   ❤️ 1
    最怕的就是没配好,程序压缩了一个,代理又解压了,完事再压缩一次
    nanmu42
        3
    nanmu42  
    OP
       2020-04-26 12:02:33 +08:00
    @qwerthhusn 对,这个问题得规避。一般是看[Content-Encoding 和 Transfer Encoding]( https://github.com/nanmu42/gzip/blob/895747f7d735b2d9ee32e8f8847377c1bc59e253/responsefilters.go#-L32-L37).
    lianyue
        4
    lianyue  
       2020-04-26 15:44:27 +08:00   ❤️ 1
    我 以前也写了个

    https://github.com/otamoe/gin-compress

    gzip + br 支持 br 的
    also24
        5
    also24  
       2020-04-26 15:52:40 +08:00 via Android   ❤️ 1
    唔… 提问一下,自己做这件事和靠 nginx 来做这件事,会有哪些差异呢?
    SingeeKing
        6
    SingeeKing  
       2020-04-26 16:38:57 +08:00   ❤️ 1
    @also24 #5 Go 哲学之不用 nginx 转发?
    imherer
        7
    imherer  
       2020-04-26 16:53:20 +08:00   ❤️ 1
    @SingeeKing 用 Caddy 吗 🐶🐶🐶
    nanmu42
        8
    nanmu42  
    OP
       2020-04-26 16:57:57 +08:00
    @also24 @SingeeKing 纯粹是萝卜青菜的喜好问题,并不分孰优孰劣,就结果来说没有什么差异。有选项总比没有选项好一些。
    imherer
        9
    imherer  
       2020-04-26 17:00:45 +08:00
    @nanmu42 试用了下,还可以,已 star

    不过有个小疑问,用 postman 请求的结果是压缩了也没用吗?
    因为我发现只有浏览器访问有效果,postman 请求的话 header 里显示已压缩了,但是大小实际没变化
    zhs227
        10
    zhs227  
       2020-04-26 17:03:19 +08:00   ❤️ 1
    @imherer postman 好像会自己解压 gz 的东西,方便你查看
    imherer
        11
    imherer  
       2020-04-26 17:11:38 +08:00
    @zhs227 哦……这样啊
    nanmu42
        12
    nanmu42  
    OP
       2020-04-26 17:11:48 +08:00
    @imherer 如果返回的 header 里有`content-encoding: gzip`,说明本条返回通过判定,成功被压缩了,`Content-Length`(如果有)这个时候是指压缩后的大小。
    imherer
        13
    imherer  
       2020-04-26 17:18:27 +08:00
    @nanmu42 嗯。content-encoding: gzip 是有的。 应该就是楼上他们说的 postman 会解压 gz 吧
    yiplee
        14
    yiplee  
       2020-04-26 17:46:23 +08:00   ❤️ 1
    一直在用 chi/middleware 里面的 compress,楼主这个也不错
    solos
        15
    solos  
       2020-04-26 18:04:00 +08:00   ❤️ 1
    nanmu42
        16
    nanmu42  
    OP
       2020-04-26 18:18:00 +08:00
    @solos 对,可惜它实在不好用,甚至不可用: https://github.com/gin-contrib/gzip/issues
    Allianzcortex
        17
    Allianzcortex  
       2020-04-26 20:26:49 +08:00   ❤️ 1
    理论上是不是核心代码两行就可以搞定...

    ```
    unc CompressGZResult(w http.ResponseWriter, r *http.Request, res interface{}) {
    w.Header().Set("Content-Type", "application/json")
    w.Header().Set("Content-Encoding", "gzip")

    gz := gzip.NewWriter(w)
    err := json.NewEncoder(gz).Encode(res)
    ```
    solos
        18
    solos  
       2020-04-26 20:35:13 +08:00
    @nanmu42 那我得换一下 哈哈
    heiheidewo
        19
    heiheidewo  
       2020-04-26 20:36:51 +08:00   ❤️ 1
    @nanmu42 我几年前就用了这个 gin-contrib/gzip,一直很稳定,这个有啥问题么
    solos
        20
    solos  
       2020-04-26 20:42:30 +08:00
    @nanmu42 我试了下 html 没有压缩 只有 json 压缩了
    nanmu42
        21
    nanmu42  
    OP
       2020-04-27 09:31:34 +08:00 via Android   ❤️ 1
    @heiheidewo @Allianzcortex
    gzip 压缩本身只是调用官方库,不难。要考虑的主演是另外的问题:
    客户端支持解压缩吗?(不支持就不能压缩)
    哪些内容类型需要压缩?判断基于 MIME 还是扩展名?(都要判断)
    数据流是不是已经压缩过?(看 header )
    返回最少要多大才值得压缩?(返回太小,压缩后更大,得不偿失)
    使用哪一个 gzip 级别?( cloudflare 做了一堆实验,nginx 直接取 1,这个问题是玄学)
    流式传输的返回该如何判断返回大小?( buffer,没别的办法,content-length 这时不存在)

    主要是脏活累活,细节问题,性能问题( GC 要友好)。

    gin-contrib 只是看上去好,它 issue 里的问题其实就是上面这些点的体现,关键是官方并不怎么上心…… (他 issue 的链接请看楼上,v2 系统不让我再发一遍了)
    nanmu42
        22
    nanmu42  
    OP
       2020-04-27 09:34:30 +08:00 via Android
    @solos 中间件默认的配置不会盲目压缩,比如返回太小不压缩(得不偿失),客户端不支持不压缩等等。详情可以看下 README 里的默认配置。
    xcstream
        23
    xcstream  
       2020-04-30 02:38:32 +08:00   ❤️ 1
    有的人喜欢在数据库里做计算,有人的人喜欢在程序里做计算。(滑稽)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5663 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 01:37 · PVG 09:37 · LAX 17:37 · JFK 20:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.