mirror of
https://github.com/fish2018/pansou.git
synced 2025-11-25 19:37:43 +08:00
135 lines
2.8 KiB
Go
135 lines
2.8 KiB
Go
|
|
package util
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"bytes"
|
|||
|
|
"compress/gzip"
|
|||
|
|
"io/ioutil"
|
|||
|
|
"strings"
|
|||
|
|
|
|||
|
|
"github.com/gin-gonic/gin"
|
|||
|
|
"pansou/config"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// 压缩响应的包装器
|
|||
|
|
type gzipResponseWriter struct {
|
|||
|
|
gin.ResponseWriter
|
|||
|
|
gzipWriter *gzip.Writer
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 实现Write接口
|
|||
|
|
func (g *gzipResponseWriter) Write(data []byte) (int, error) {
|
|||
|
|
return g.gzipWriter.Write(data)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 实现WriteString接口
|
|||
|
|
func (g *gzipResponseWriter) WriteString(s string) (int, error) {
|
|||
|
|
return g.gzipWriter.Write([]byte(s))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 关闭gzip写入器
|
|||
|
|
func (g *gzipResponseWriter) Close() {
|
|||
|
|
g.gzipWriter.Close()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GzipMiddleware 返回一个Gin中间件,用于压缩HTTP响应
|
|||
|
|
func GzipMiddleware() gin.HandlerFunc {
|
|||
|
|
return func(c *gin.Context) {
|
|||
|
|
// 如果未启用压缩,直接跳过
|
|||
|
|
if !config.AppConfig.EnableCompression {
|
|||
|
|
c.Next()
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查客户端是否支持gzip
|
|||
|
|
if !strings.Contains(c.Request.Header.Get("Accept-Encoding"), "gzip") {
|
|||
|
|
c.Next()
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建一个缓冲响应写入器
|
|||
|
|
buffer := &bytes.Buffer{}
|
|||
|
|
blw := &bodyLogWriter{body: buffer, ResponseWriter: c.Writer}
|
|||
|
|
c.Writer = blw
|
|||
|
|
|
|||
|
|
// 处理请求
|
|||
|
|
c.Next()
|
|||
|
|
|
|||
|
|
// 获取响应内容
|
|||
|
|
responseData := buffer.Bytes()
|
|||
|
|
|
|||
|
|
// 如果响应大小小于最小压缩大小,直接返回原始内容
|
|||
|
|
if len(responseData) < config.AppConfig.MinSizeToCompress {
|
|||
|
|
c.Writer.Write(responseData)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置gzip响应头
|
|||
|
|
c.Header("Content-Encoding", "gzip")
|
|||
|
|
c.Header("Vary", "Accept-Encoding")
|
|||
|
|
|
|||
|
|
// 创建gzip写入器
|
|||
|
|
gz, err := gzip.NewWriterLevel(c.Writer, gzip.BestSpeed)
|
|||
|
|
if err != nil {
|
|||
|
|
c.Writer.Write(responseData)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
defer gz.Close()
|
|||
|
|
|
|||
|
|
// 写入压缩内容
|
|||
|
|
gz.Write(responseData)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// bodyLogWriter 是一个用于记录响应体的写入器
|
|||
|
|
type bodyLogWriter struct {
|
|||
|
|
gin.ResponseWriter
|
|||
|
|
body *bytes.Buffer
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Write 实现ResponseWriter接口
|
|||
|
|
func (w bodyLogWriter) Write(b []byte) (int, error) {
|
|||
|
|
w.body.Write(b)
|
|||
|
|
return w.ResponseWriter.Write(b)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// WriteString 实现ResponseWriter接口
|
|||
|
|
func (w bodyLogWriter) WriteString(s string) (int, error) {
|
|||
|
|
w.body.WriteString(s)
|
|||
|
|
return w.ResponseWriter.WriteString(s)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CompressData 压缩数据
|
|||
|
|
func CompressData(data []byte) ([]byte, error) {
|
|||
|
|
var buf bytes.Buffer
|
|||
|
|
|
|||
|
|
// 创建gzip写入器
|
|||
|
|
gz, err := gzip.NewWriterLevel(&buf, gzip.BestSpeed)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 写入数据
|
|||
|
|
if _, err := gz.Write(data); err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 关闭写入器
|
|||
|
|
if err := gz.Close(); err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return buf.Bytes(), nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// DecompressData 解压数据
|
|||
|
|
func DecompressData(data []byte) ([]byte, error) {
|
|||
|
|
// 创建gzip读取器
|
|||
|
|
gz, err := gzip.NewReader(bytes.NewReader(data))
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
defer gz.Close()
|
|||
|
|
|
|||
|
|
// 读取解压后的数据
|
|||
|
|
return ioutil.ReadAll(gz)
|
|||
|
|
}
|