Files
pansou/util/compression.go
fish2018 5004e4f99f update
2025-07-12 19:53:44 +08:00

135 lines
2.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}