mirror of
https://github.com/fish2018/pansou.git
synced 2025-11-25 03:14:59 +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)
|
||
} |