Skip to content

Commit

Permalink
Merge pull request #13 from BadKid90s/gzip
Browse files Browse the repository at this point in the history
feat(main): 增加Gzip压缩中间件
  • Loading branch information
BadKid90s authored Jan 29, 2024
2 parents ba79ea0 + d93cf7b commit 87b2ba1
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 2 deletions.
33 changes: 31 additions & 2 deletions example/base/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"fmt"
"knife"
"knife/middleware"
"log"
Expand All @@ -12,16 +13,22 @@ func main() {

//Create a middleware chain
//first plan
chain := planOne()
//chain := planOne()

//second plan
//chain := planTwo()

//the third plan
//chain := planThree()

//gzip middleware
chain := gzip()

//start serve
_ = http.ListenAndServe(":8080", chain)
err := http.ListenAndServe(":8080", chain)
if err != nil {
panic(err)
}
}

// plan one
Expand Down Expand Up @@ -81,3 +88,25 @@ func planThree() *knife.Chain {

return chain
}

func gzip() *knife.Chain {
chain := knife.NewChain().
Use(middleware.Logger()).
Use(middleware.Recover()).
//Use(middleware.GzipDefault()).
Use(middleware.Gzip(1024)).
Use(func(context *knife.Context) {
data := "Gzip是一种压缩文件格式并且也是一个在类 Unix 上的一种文件解压缩的软件,通常指GNU计划的实现,此处的gzip代表GNU zip。" +
"也经常用来表示gzip这种文件格式。软件的作者是Jean-loup Gailly和Mark Adler。在1992年10月31日第一次公开发布,版本号0.1,1993年2月,发布了1.0版本。" +
"Gzip是一种压缩文件格式并且也是一个在类 Unix 上的一种文件解压缩的软件,通常指GNU计划的实现,此处的gzip代表GNU zip。" +
"也经常用来表示gzip这种文件格式。软件的作者是Jean-loup Gailly和Mark Adler。在1992年10月31日第一次公开发布,版本号0.1,1993年2月,发布了1.0版本。" +
"Gzip是一种压缩文件格式并且也是一个在类 Unix 上的一种文件解压缩的软件,通常指GNU计划的实现,此处的gzip代表GNU zip。" +
"也经常用来表示gzip这种文件格式。软件的作者是Jean-loup Gailly和Mark Adler。在1992年10月31日第一次公开发布,版本号0.1,1993年2月,发布了1.0版本。"
_, err := context.Writer.Write([]byte(data))
if err != nil {
panic(fmt.Sprintf("writer data error %s", err))
}
context.Writer.WriteHeader(http.StatusOK)
})
return chain
}
62 changes: 62 additions & 0 deletions knife/middleware/gzip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package middleware

import (
"bytes"
"compress/gzip"
"knife"
)

// GzipDefault 当响应体的大小超过100kb后,进行gzip压缩
func GzipDefault() knife.MiddlewareFunc {
return Gzip(100 * 1024)
}

// Gzip 对响应的数据进行压缩
// response Header 设置 Accept-Encoding=gzip ,说明响应的数据是gzip压缩过的,需要客户端进行gzip解压
// gzipMinLength 是设置响应体大小的阈值,超过这个阈值会进行响应数据的压缩
func Gzip(gzipMinLength int) knife.MiddlewareFunc {
return func(context *knife.Context) {
writer := context.Writer
context.Writer = &gzipResponseWriter{
HttpResponseWriter: writer,
gzipMinLength: gzipMinLength,
}
context.Next()
}
}

// 自定义的ResponseWriter,将数据写入gzip.Writer
type gzipResponseWriter struct {
knife.HttpResponseWriter
gzipMinLength int
}

// 重写Write方法,将数据写入gzip.Writer
func (w *gzipResponseWriter) Write(data []byte) (int, error) {

beforeSize := len(data)
if beforeSize > w.gzipMinLength {
// 添加 gzip 头部
w.Header().Set("Content-Encoding", "gzip")

// 调用gzip.Writer的Write方法,将数据压缩后写入到底层的http.ResponseWriter
var zBuf bytes.Buffer
zw := gzip.NewWriter(&zBuf)
if n, err := zw.Write(data); err != nil {
err := zw.Close()
if err != nil {
return n, err
}
knife.Logger.Printf("gzip is failed,err: %s", err)
}
err := zw.Close()
if err != nil {
return 0, err
}
afterData := zBuf.Bytes()
knife.Logger.Printf("gzip success,befor size: %d, after size: %d", beforeSize, len(afterData))

return w.HttpResponseWriter.Write(afterData)
}
return w.HttpResponseWriter.Write(data)
}

0 comments on commit 87b2ba1

Please sign in to comment.