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

最新文章

  1. 前端学HTTP之网关、隧道和中继
  2. Azure Site to Site VPN 配置手册
  3. 理解Cookie和Session机制(转)
  4. C++时间函数模板
  5. Hibernate逍遥游记-第5章映射一对多-02双向(<set>、<key>、<one-to-many>、inverse、cascade="all-delete-orphan")
  6. 日志收集框架 Exceptionless
  7. CIC and Fir 滤波器的级联
  8. Linux环境Perl链接MS Sql Server数据库
  9. django-debug-toolbar使用指南
  10. Linux运维基础
  11. 解析Json文件
  12. VMware 物理机可以复制文件到虚拟机,却无法从虚拟机复制文件到物理机(已解决)
  13. vue.js 进行初始化遇到的关于core-js的错误@core-js/modules/es6.array.find-index]
  14. Javascript你必须要知道的面试题
  15. zabbix agentd安装
  16. python抽象方法
  17. 背水一战 Windows 10 (52) - 控件(集合类): ItemsControl - 自定义 ItemsControl, 自定义 ContentPresenter
  18. UVa 1354 天平难题
  19. Python对list去重
  20. Codeforces Round #361 (Div. 2) B. Mike and Shortcuts bfs

热门文章

  1. CUDA编程(十)使用Kahan's Summation Formula提高精度
  2. delphi的万能数据库操作
  3. MVC Web Api 发布到Azure报错
  4. ubuntu mysql5.7源码安装
  5. 关于intent传递对象后是传递的对象的地址还是对象的拷贝?
  6. memcached value最大限制只能是1M吗
  7. JavaScript对象模型-执行模型
  8. 详解Python的*args和 **kwargs
  9. json 获取属性值
  10. ubuntu12.04向左边栏添加图标(引用)