浅析negroni-gzip 过滤器的源码

来源:互联网 发布:向日葵软件下载 编辑:程序博客网 时间:2024/06/02 03:16
  • 源码来源:negroni-gzip

  • gzip能对数据进行压缩,从而使服务端向客户端传输数据的速度加快。以下对源码的分析是基于源码注释加上自己在谷歌上搜索入header和Sec-WebSocket-Key等知识后的理解,由于时间原因没有深入使用过gzip,很可能存在错误请指正~

// 以下的压缩常量来自于compress/gzip 包const (    encodingGzip = "gzip" // 编码方式为gzip    // request或response的header    headerAcceptEncoding  = "Accept-Encoding" // 指定浏览器可以支持的web服务器返回内容压缩编码类型    headerContentEncoding = "Content-Encoding" //web服务器支持的返回内容压缩编码类型    headerContentLength   = "Content-Length" // 响应体的长度    headerContentType     = "Content-Type" // 返回内容的MIME类型    headerVary            = "Vary"    headerSecWebSocketKey = "Sec-WebSocket-Key"    // 压缩级别    BestCompression    = gzip.BestCompression    BestSpeed          = gzip.BestSpeed    DefaultCompression = gzip.DefaultCompression    NoCompression      = gzip.NoCompression)// gzipResponseWriter 包含 negroni.ResponseWritertype gzipResponseWriter struct {    w *gzip.Writer    negroni.ResponseWriter    wroteHeader bool}// 检查并设置response的header,并把wroteHeader 设为true,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}// 把byte数据写入 gzip.Writer并设置Content-Typefunc (grw *gzipResponseWriter) Write(b []byte) (int, error) {    if !grw.wroteHeader {// 判断是否已经设置过了response的header        grw.WriteHeader(http.StatusOK) // 默认返回码200    }    if grw.w == nil {        return grw.ResponseWriter.Write(b)    }    // 设置Content-Type    if len(grw.Header().Get(headerContentType)) == 0 {        grw.Header().Set(headerContentType, http.DetectContentType(b))    }    return grw.w.Write(b)}// handler结构体包含ServeHTTP方法,sync.Pool用来缓存对象type handler struct {    pool sync.Pool}// 根据压缩level来进行,返回一个handler去处理ServeHTTP中的gzip压缩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以包括http.ResponseWriterfunc (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {    // 判断客户端的AcceptEncoding,如果不接受gzip的编码格式则跳过压缩    if !strings.Contains(r.Header.Get(headerAcceptEncoding), encodingGzip) {        next(w, r)        return    }    // 如果客户端是发送Sec-WebSocket-Key过来也无需压缩 if len(r.Header.Get(headerSecWebSocketKey)) > 0 {        next(w, r)        return    }    gz := h.pool.Get().(*gzip.Writer)// 从pool中获取Writer    defer h.pool.Put(gz)// 使用完后放回pool池等待重新被利用    gz.Reset(w)// 用ResponseWriter完成Reset    // 新建一个包含negroni.ResponseWriter和Write的gzipResponseWriter对象,并把wroteHeader初始化为false    nrw := negroni.NewResponseWriter(w)    grw := gzipResponseWriter{gz, nrw, false}    // gzipResponseWriter取代原来的中间件去应用下一个handlerFunc    next(&grw, r)    // 删除header的ContentLength    grw.Header().Del(headerContentLength)    gz.Close()}
原创粉丝点击