negroni-gzip源码简单分析解读

这是一个为Negroni设计的gzip压缩处理中间件,需要用到已有的compress中的gzip,阅读了不长的源码之后,总结了一些关键要点和注意点。

  • 检查是否有潜在的已经被预先解码的但却不可用的response。在主体部分被写之前,要先写头。注意:Discard 是一个 io.Writer,对它进行的任何 Write 调用都将无条件成功。ioutil.Discard不记录copy得到的数值。

      func (grw *gzipResponseWriter) WriteHeader(code int) {
    headers := grw.ResponseWriter.Header()
    if headers.Get(headerContentEncoding) == "" {
    headers.Set(headerContentEncoding, encodingGzip)
    headers.Add(headerVary, headerAcceptEncoding)
    } else {
    grw.w.Reset(ioutil.Discard)
    grw.w = nil
    }
    grw.ResponseWriter.WriteHeader(code)
    grw.wroteHeader = true
    }
  • 向gzip.Writer中写入字节流。如果头的Content-Type还没有被设置,则用net/http库中的类型检测来完成。

      func (grw *gzipResponseWriter) Write(b []byte) (int, error) {
    if !grw.wroteHeader {
    grw.WriteHeader(http.StatusOK)
    }
    if grw.w == nil {
    return grw.ResponseWriter.Write(b)
    }
    if len(grw.Header().Get(headerContentType)) == 0 {
    grw.Header().Set(headerContentType, http.DetectContentType(b))
    }
    return grw.w.Write(b)
    }
  • 一个sync.Pool对象就是一组临时对象的集合,Pool用于存储那些被分配了但是没有被使用,而未来可能会使用的值,以减小垃圾回收的压力。

      type handler struct {
    pool sync.Pool
    }
  • Gzip返回一个handler来处理在ServeHTTP中的压缩,需要调用gzip库的NewWriterLevel方法。

      func Gzip(level int) *handler {
    h := &handler{}
    h.pool.New = func() interface{} {
    gz, err := gzip.NewWriterLevel(ioutil.Discard, level)
    if err != nil {
    panic(err)
    }
    return gz
    }
    return h
    }
  • ServeHTTP中如果客户端不接受gzip的编码方式,则会跳过不压缩。如果客户端在尝试WebSocket连接时,也会不压缩。

      if !strings.Contains(r.Header.Get(headerAcceptEncoding), encodingGzip) {
    next(w, r)
    return
    } if len(r.Header.Get(headerSecWebSocketKey)) > 0 {
    next(w, r)
    return
    }
  • 从pool中遍历writer,如果之后遇到的错误,就通过defer的方法,返回pool,用ResponseWriter重置,这让我们可以再利用已经被分配的buffer,而不是为每一个单独的请求开辟新的buffer。

      gz := h.pool.Get().(*gzip.Writer)
    defer h.pool.Put(gz)
    gz.Reset(w)
  • 用negroni.ResponseWriter打包原来的ResponseWriter,并创建一个新的gzipResponseWriter,并且调用下一个handler。为了安全,在得知写步骤执行完之后删除内容的大小信息,最后记得关闭gz。

      nrw := negroni.NewResponseWriter(w)
    grw := gzipResponseWriter{gz, nrw, false} next(&grw, r) grw.Header().Del(headerContentLength) gz.Close()
  • 在使用negroni-gzip的时候,要注意在另外改变response body的中间件之前使用Gzip中间件,比如应该先用Gzip,再用NewStatic。

      n := negroni.New()
    n.Use(negroni.NewRecovery())
    n.Use(negroni.NewLogger())
    n.Use(gzip.Gzip(gzip.DefaultCompression))
    n.Use(negroni.NewStatic(http.Dir("public")))

negroni-gzip源码简单分析解读的更多相关文章

  1. FFmpeg源码简单分析:结构体成员管理系统-AVOption

    ===================================================== FFmpeg的库函数源码分析文章列表: [架构图] FFmpeg源码结构图 - 解码 FFm ...

  2. FFmpeg的HEVC解码器源码简单分析:解析器(Parser)部分

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

  3. FFmpeg源码简单分析:libswscale的sws_scale()

    ===================================================== FFmpeg的库函数源码分析文章列表: [架构图] FFmpeg源码结构图 - 解码 FFm ...

  4. Django-session中间件源码简单分析

    Django-session中间件源码简单分析 settings里有关中间件的配置 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddlew ...

  5. FFmpeg的HEVC解码器源码简单分析:概述

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

  6. FFmpeg的HEVC解码器源码简单分析:解码器主干部分

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

  7. urllib源码简单分析

    对下面这段代码做分析 import urllib params = urllib.urlencode({'wd': 'python'}) f = urllib.urlopen("http:/ ...

  8. CardboardSDK-iOS 源码简单分析

    该项目地址: 地址 克隆地址为 https://github.com/rsanchezsaez/CardboardSDK-iOS.git 目前如果想在iOS设备上实现双目VR的功能,Google 已经 ...

  9. MongoDB 默认写入关注保存数据丢失问题与源码简单分析

    MongoDB 默认写入关注可能保存数据丢失问题分析 问题描述: EDI服务进行优化,将原有MQ发送成功并且DB写入成功,两个条件都达成,响应接收订单数据成功,修改为只有有一个条件成功就响应接收数据成 ...

随机推荐

  1. Android——SlidingMenu学习总结

    来源 SlidingMenu是github上比較火开源库.很强大,不但但是简单的设置实现两側滑动菜单,还能够设置菜单的阴影.渐变色.划动模式等. 下载地址:https://github.com/jfe ...

  2. Tcl学习之--列表|字典

    [列表|字典] Tcl使用列表来处理各种集合,比方一个目录中的全部文件,以及一个组件的全部选项.最简单的列表就是包括由随意个空格.制表符.换行符.分隔的随意多个元素的字符串.比方: JerryAlic ...

  3. 各种“GND”

    资料来自网上,把个人觉得靠谱的摘取下来 1.地分类: a)直流地:直流电路“地”,零电位参考点: b)交流地:交流电的零线.要与地线区别开,不过,有时候拉电入户之前会把地线和零线接在一起: c)功率地 ...

  4. IE9版本号下面ajax 跨域问题解决

    ajax跨域请求数据在谷歌火狐我本地IE11都是没问题的. 让測试就发现问题了,IE8下请求不到数据.然后我查看一下自己写的js看有没有不兼容问题.但是都没有啊.为什么就请求不到呢. 我把ajax的e ...

  5. hdu1507——Uncle Tom's Inherited Land*

    Uncle Tom's Inherited Land* Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (J ...

  6. Sql数据库查询语言

    1.概述 Sql是一种面向数据库的结构化查询语言.是符合美国国家标准化组织ANSI的一种计算机标准语言. Sql具对数据库的操作有:增删改查.创建数据库.创建表.创建存储过程.创建视图等 RDBMS关 ...

  7. git 团队代码管理交流共同进步

    Installation methods for GitLab | GitLab https://about.gitlab.com/installation/#centos-7 gittutorial ...

  8. mysql13---索引使用注意

    .4唯一索引 ①当表的某列被指定为unique约束时,这列就是一个唯一索引 ) unique); 这时, name 列就是一个唯一索引. unique字段可以为NULL,并可以有多NULL(,null ...

  9. 常用的机器学习&数据挖掘知识点总结

    Basis(基础): MSE(Mean Square Error 均方误差),LMS(LeastMean Square 最小均方),LSM(Least Square Methods 最小二乘法),ML ...

  10. 关于数论【polya计数法】

    可以预见数论推公式是有多么蛋疼. 让我简明扼要的讲讲吧(多都说不出来,毕竟才做了两道题)其实呢,这个算法应该归入群论,有个有用的东西:置换群,它表示一个集合包括很多的置换.先讲讲置换吧:↓(这是个置换 ...