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. csv读入数据,用julia/matplotlib/pyplot 画矢量图导入word中

    这是是用julia来实现画图.julia有三个画图库:Winston.Gadfly.PyPlot 这里用的是pyplot,事实上他是基于matplotlib的 1.首先在juno里安装两个库 juno ...

  2. Ubuntu下配置Tomcat以指定(非root)身份执行

    My Blog:http://www.outflush.com/ 通常情况下.在配置Tomcat生产环境时,一般会配置Tomcat以特定的身份执行(非root).这样有利于提高安全性,防止站点被黑后的 ...

  3. POJ3761 Bubble Sort

    对1~n组成的序列进行冒泡排序,一共进行了k趟,问有几个符合题意的序列. 注意:这里指每一趟是指交换当前相邻的全部逆序对,比如:2 1 4 3进行一趟交换就是1 2 3 4 假设我们细心观察.就会发现 ...

  4. Codeforces 768 E. Game of Stones 博弈DP

    E. Game of Stones   Sam has been teaching Jon the Game of Stones to sharpen his mind and help him de ...

  5. spring boot redis缓存入门

    摘要: 原创出处 泥瓦匠BYSocket 下载工程 springboot-learning-example ,工程代码注解很详细.JeffLi1993/springboot-learning-exam ...

  6. ABAP WEBRFC

    通过WEBRFC实现在网页下载SMW0上传的文件 FUNCTION zhr_download_test. *"---------------------------------------- ...

  7. lambda和抽象类

    lambda的使用条件是‘一个接口仅有一个待实现的方法’: so,lambda不能使用在抽象类上,使用后或提示‘Target type of a lambda conversion must be a ...

  8. 将多个jar合并为一个jar

    有时候,我们需要将多个jar合并为一个jar,ant提供了这样的一个功能 build.xml文件如下 执行以上任务会将 当前目录下的 mysql.jar,commons-io.jar合并为一个 all ...

  9. Masonry 比例(multipliedBy)

    前言 说到iOS自动布局,有很多的解决办法.有的人使用xib/storyboard自动布局,也有人使用frame来适配.对于前者,笔者并不喜欢,也不支持.对于后者,更是麻烦,到处计算高度.宽度等,千万 ...

  10. pandas 学习 —— 逻辑表达式与布尔索引

    >> df = pd.DataFrame(np.random.randint(0, 10, (5, 4)), columns=list('ABCD')) A B C D 0 0 4 8 4 ...