forked from wheelcomplex/kmg
/
Compress.go
executable file
·117 lines (108 loc) · 3.42 KB
/
Compress.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package kmgHttp
import (
"compress/flate"
"compress/gzip"
"github.com/bronze1man/kmg/kmgCompress"
"io"
"net/http"
"strconv"
"strings"
)
type ResponseWriterWraper struct {
io.Writer
http.ResponseWriter
}
// TODO 这个地方缺少猜类型功能,导致不能直接wrapper到任意Handler上去.(会导致 html Type 错误.)
// TODO 有时候压缩会有负效果,此处应该可以自动判断出来.
func (w ResponseWriterWraper) Write(b []byte) (int, error) {
return w.Writer.Write(b)
}
func CompressHandlerFunc(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
acceptEncoding := r.Header.Get("Accept-Encoding")
switch {
case strings.Contains(acceptEncoding, "deflate"):
w.Header().Set("Content-Encoding", "deflate")
gzw, err := flate.NewWriter(w, -1)
if err != nil {
panic(err)
}
defer gzw.Close()
gzr := ResponseWriterWraper{Writer: gzw, ResponseWriter: w}
f(gzr, r)
return
case strings.Contains(acceptEncoding, "gzip"):
w.Header().Set("Content-Encoding", "gzip")
gzw := gzip.NewWriter(w)
defer gzw.Close()
gzr := ResponseWriterWraper{Writer: gzw, ResponseWriter: w}
f(gzr, r)
return
default:
f(w, r)
}
}
}
func CompressHandler(fn http.Handler) http.Handler {
return http.HandlerFunc(CompressHandlerFunc(fn.ServeHTTP))
}
// a flate(DEFLATE) compress wrap around http request and response,
// !!not handle any http header!!
func HttpHandleCompressFlateWrap(fn http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
oldBody := r.Body
defer oldBody.Close()
r.Body = flate.NewReader(oldBody)
//w.Header().Set("Content-Encoding", "deflate")
gzw, err := flate.NewWriter(w, -1)
if err != nil {
panic(err)
}
defer gzw.Close()
gzr := ResponseWriterWraper{Writer: gzw, ResponseWriter: w}
fn.ServeHTTP(gzr, r)
})
}
// a flate(DEFLATE) compress wrap around http request and response,
// !!not handle any http header!!
func HttpHandleCompressGzipWrap(fn http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
oldBody := r.Body
defer oldBody.Close()
var err error
r.Body, err = gzip.NewReader(oldBody)
if err != nil {
panic(err)
}
//w.Header().Set("Content-Encoding", "gzip")
gzw := gzip.NewWriter(w)
defer gzw.Close()
gzr := ResponseWriterWraper{Writer: gzw, ResponseWriter: w}
fn.ServeHTTP(gzr, r)
})
}
// 如果使用了这个,golang的猜测返回类型的东西会挂掉.请设置输出的内容的类型
// 这个地方返回错误没有什么意义,(调用者无法处理)
func CompressWriteByte(r *http.Request, w http.ResponseWriter, b []byte) {
acceptEncoding := r.Header.Get("Accept-Encoding")
switch {
case strings.Contains(acceptEncoding, "deflate"):
w.Header().Set("Content-Encoding", "deflate")
b = kmgCompress.FlateMustCompress(b)
w.Header().Set("Content-Length", strconv.Itoa(len(b)))
w.Write(b)
return
case strings.Contains(acceptEncoding, "gzip"):
w.Header().Set("Content-Encoding", "gzip")
b = kmgCompress.GzipMustCompress(b)
w.Header().Set("Content-Length", strconv.Itoa(len(b)))
w.Write(b)
default:
w.Header().Set("Content-Length", strconv.Itoa(len(b)))
w.Write(b)
}
}
func CompressWriteHtml(req *http.Request, w http.ResponseWriter, html []byte) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
CompressWriteByte(req, w, html)
}