zoukankan      html  css  js  c++  java
  • negroni-gzip源码简单分析解读

    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")))
  • 相关阅读:
    转 -- Linux系列:Ubuntu虚拟机设置固定IP上网(配置IP、网关、DNS、防止resolv.conf被重写)
    转 -- 求一个二进制数值中的1的个数
    ubuntu 搭建 samba 服务器
    64bit ubuntu 安装32bit的软件
    ubuntu 添加管理员账户
    #ifdef 和 #if defined 的区别 -- 转
    xming + putty 搭建远程图形化ssh访问ubuntu 14.04
    ubuntu 安装bochs
    强制类型转换中的精度丢失
    转载 -- 如何判断Javascript对象是否存在
  • 原文地址:https://www.cnblogs.com/renleimlj/p/7887303.html
Copyright © 2011-2022 走看看