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")))
negroni-gzip源码简单分析解读的更多相关文章
- FFmpeg源码简单分析:结构体成员管理系统-AVOption
===================================================== FFmpeg的库函数源码分析文章列表: [架构图] FFmpeg源码结构图 - 解码 FFm ...
- FFmpeg的HEVC解码器源码简单分析:解析器(Parser)部分
===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...
- FFmpeg源码简单分析:libswscale的sws_scale()
===================================================== FFmpeg的库函数源码分析文章列表: [架构图] FFmpeg源码结构图 - 解码 FFm ...
- Django-session中间件源码简单分析
Django-session中间件源码简单分析 settings里有关中间件的配置 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddlew ...
- FFmpeg的HEVC解码器源码简单分析:概述
===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...
- FFmpeg的HEVC解码器源码简单分析:解码器主干部分
===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...
- urllib源码简单分析
对下面这段代码做分析 import urllib params = urllib.urlencode({'wd': 'python'}) f = urllib.urlopen("http:/ ...
- CardboardSDK-iOS 源码简单分析
该项目地址: 地址 克隆地址为 https://github.com/rsanchezsaez/CardboardSDK-iOS.git 目前如果想在iOS设备上实现双目VR的功能,Google 已经 ...
- MongoDB 默认写入关注保存数据丢失问题与源码简单分析
MongoDB 默认写入关注可能保存数据丢失问题分析 问题描述: EDI服务进行优化,将原有MQ发送成功并且DB写入成功,两个条件都达成,响应接收订单数据成功,修改为只有有一个条件成功就响应接收数据成 ...
随机推荐
- leetcode——Implement strStr() 实现字符串匹配函数(AC)
Implement strStr(). Returns a pointer to the first occurrence of needle in haystack, or null if need ...
- hdu2222--Keywords Search+AC自己主动机模板
题目链接:pid=2222">点击进入 KMP对模式串进行处理.然后就能够方便的推断模式串是否在目标串中出现了:这显示适合一个模式串多个目标串的情况.可是假设模式串有多个,这时假设还用 ...
- HttpWebRequest中的ContentType详解
1.参考网络资源: http://blog.csdn.net/blueheart20/article/details/45174399 ContentType详解 http://www.tuicoo ...
- /tmp/crontab.tDoyrp: 设备上没有空间 查看文件夹所在分区 磁盘剩余空间 15g的root-mail大文件
问题诊断: 文件夹所在磁盘已满 问题确认: 查看文件夹所在磁盘剩余空间,找出空间被消耗的文件(集) 查看文件夹所在磁盘空间的所属文件(暂未解决) [root@hadoop1 /]# df -Bg /t ...
- linux 多个文件中查找字符串 hadoop 3 安装 调试
http://www.cnblogs.com/iLoveMyD/p/4281534.html 2015年2月9日 14:36:38 # find <directory> -type f - ...
- IsNumeric 判断字符串是否为数字(使用Val函数实现),这个函数相当于Java的IsNaN函数
IsNumeric 判断字符串是否为数字,如果是数字返回true,如果包含有汉字或字符的话返回false. 由于Delphi本身没有IsNumeric这个函数,不像其它语言,这个函数相当于Java的I ...
- lambda和抽象类
lambda的使用条件是‘一个接口仅有一个待实现的方法’: so,lambda不能使用在抽象类上,使用后或提示‘Target type of a lambda conversion must be a ...
- C语言-1.结构体,2.枚举,3.typedef,4.预处理指令的概念,5.条件编译
1. 结构体数组 定义:由若干个相同类型的结构体变量组成的有序的集合. 定义格式: 1) 定义结构体的同时定义结构体数组 struct Car{ int lunzi; int speed; }cars ...
- [USACO17FEB]Why Did the Cow Cross the Road II
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4990 [算法] 首先记录b中每个数的出现位置 , 记为P 对于每个ai , 枚举(a ...
- 协议森林02 小喇叭开始广播 (以太网与WiFi协议)
作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁任何形式转载. “小喇叭开始广播啦”,如果你知道这个,你一定是老一辈的人.“小喇叭”是五十年代到八十年代的儿童广播 ...