Go的gzip包的简单解析和gbk包的实现
来源:互联网 发布:剑帝莱维 知乎 编辑:程序博客网 时间:2024/05/16 13:04
Go的gzip包的简单解析和gbk包的实现
- gzip包的解析
- gbk包的粗略实现(待测试)
a.首先看一下gzip包
这里gzip包有几个内容
首先是几个结构
type gzipResponseWriter struct { w *gzip.Writer negroni.ResponseWriter wroteHeader bool}type handler struct { pool sync.Pool}
然后是几个函数
func (grw *gzipResponseWriter) WriteHeader(code int)func (grw *gzipResponseWriter) Write(b []byte) (int, error)func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)func Gzip(level int) *handler
b.函数的解析
由上次我们解析Negroni库可知关键在ServeHttp,我们来看看它的代码
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { // Skip compression if the client doesn't accept gzip encoding. if !strings.Contains(r.Header.Get(headerAcceptEncoding), encodingGzip) { next(w, r) return } // Skip compression if client attempt WebSocket connection if len(r.Header.Get(headerSecWebSocketKey)) > 0 { next(w, r) return } // Retrieve gzip writer from the pool. Reset it to use the ResponseWriter. // This allows us to re-use an already allocated buffer rather than // allocating a new buffer for every request. // We defer g.pool.Put here so that the gz writer is returned to the // pool if any thing after here fails for some reason (functions in // next could potentially panic, etc) gz := h.pool.Get().(*gzip.Writer) defer h.pool.Put(gz) gz.Reset(w) // Wrap the original http.ResponseWriter with negroni.ResponseWriter // and create the gzipResponseWriter. nrw := negroni.NewResponseWriter(w) grw := gzipResponseWriter{gz, nrw, false} // Call the next handler supplying the gzipResponseWriter instead of // the original. next(&grw, r) // Delete the content length after we know we have been written to. grw.Header().Del(headerContentLength) gz.Close()}
这里我们看到,该函数首先根据request的情况做相应判断,然后从sync池取出Writer并且reset使用它,然后就把next中的responseWriter替换为本文件中的grw,相当于做了一层代理,这样当http请求如果用到Write方法或者WriteHead方法时使用的就是这里实现的对应方法。
c.接下来我们看看WriteHead和Write函数
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}
可以看到,根据条件,我们设置对应的grw,当header里的ContentEncoding为空时设置对应的参数,否则把grw的gzip.Writer置为nil,然后调用negrino的responseWriter的WriteHeader方法
接下来我们看看Write方法
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)}
这个函数也很好理解,当gzip.Writer是nil的时候说明不用gzip就使用grw.ResponseWriter.Write(b),然后是否已经写了头部等等。。。
至于最后的Gzip它是返回一个handle这里也就不详述了
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}
小结
通过以上代码分析和根据之前我们另一篇博客对negroni的分析,当http调用ServeHttp的时候,该包会用grw代理原来的responseWrite于是到后面使用Write方法的时候就可以同gzip方式了,利用这种思维我模仿写了一个gbk(未测试)
gbk包
这是github地址https://github.com/caijh23/goWeb/tree/master/web/negroni-gbk
这是代码
package gbkimport ( "net/http" "strings" "io/ioutil" "golang.org/x/text/transform" "golang.org/x/text/encoding/simplifiedchinese" "github.com/urfave/negroni")const ( headerContentType = "Content-type" encodingGbk = "gbk" encodingUTF8 = "UTF-8")type gbkResponseWriter struct { w *transform.Writer negroni.ResponseWriter wroteHeader bool}func (grw *gbkResponseWriter) WriteHeader(code int) { headers := grw.ResponseWriter.Header() if headers.Get(headerContentType) == "" { headers.Set(headerContentType,encodingGbk) } else if strings.Contains(headers.Get(headerContentType),encodingUTF8) { headers.Set(headerContentType,strings.Replace(headers.Get(headerContentType),encodingUTF8,encodingGbk,-1)) } else { grw.w = nil } grw.ResponseWriter.WriteHeader(code) grw.wroteHeader = true}func (grw *gbkResponseWriter) 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)}type handler struct {}func Gbk() *handler { h := &handler{} return h}func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { if len(r.Header.Get(headerContentType)) == 0 { next(w, r) return } var nrw negroni.ResponseWriter var gb *transform.Writer if strings.Contains(r.Header.Get(headerContentType), encodingUTF8) { nrw = negroni.NewResponseWriter(w) gb = transform.NewWriter(nrw, nil) } if strings.Contains(r.Header.Get(headerContentType), encodingGbk) { rd := transform.NewReader(r.Body, simplifiedchinese.GBK.NewDecoder()) r.Body = ioutil.NopCloser(rd) nrw = negroni.NewResponseWriter(w) gb = transform.NewWriter(nrw, simplifiedchinese.GBK.NewEncoder()) } grw := gbkResponseWriter{gb, nrw, false} next(&grw, r)}
阅读全文
0 0
- Go的gzip包的简单解析和gbk包的实现
- 使用go读取gzip格式的压缩包
- Go?GO!(三) Go的面向对象技术、并发和包的简单介绍
- Go的MongoDB包
- go的http包
- Go的unsafe包
- Go的reflect机制和reflect包
- Go 的 flag 包可以解析命令行的参数
- go 的包安装准备
- Go的http包详解
- go语言的http包
- Go语言的os包
- go的log4go日志包
- Go的http包详解
- Go 的反射包浅析
- 可用于J2ME的GZip算法包
- Go语言备忘录:net/http包的使用模式和源码解析
- go语言的官方包sync.Pool的实现原理和适用场景
- leetCode-Longest Continuous Increasing Subsequence
- UIView子view随父view同步变化
- iTunes_12.7 && iPhone && 自定义铃声
- 操作符和表达式
- 我和我所理解的链队列
- Go的gzip包的简单解析和gbk包的实现
- 二路归并排序
- springboot入门(三)-- springboot集成mybatis及mybatis generator工具使用
- 论坛的创建
- php中的类型转换
- Hibernate二级缓存
- MT5 Gateway API 行情与交易流通性完成
- OS ##并发程序设计
- Android AsyncTask介绍和一个简单的小例子