perf(compression): pre-compute MIME type byte slices for isCompressible

Add typesBytes and typesWildcardPrefix fields to Middleware, built once
at construction. isCompressible now uses pre-converted byte slices
instead of allocating []byte(t) per comparison per request.
This commit is contained in:
xfy 2026-06-04 11:09:08 +08:00
parent bd97c05d0d
commit e5fa9fe9de

View File

@ -112,6 +112,10 @@ type Middleware struct {
brotliPool *compressorPool
// types 可压缩的 MIME 类型列表
types []string
// typesBytes 预计算的小写 MIME 类型字节切片
typesBytes [][]byte
// typesWildcardPrefix 预计算的通配符前缀字节切片
typesWildcardPrefix [][]byte
// level 压缩级别1-9
level int
@ -171,6 +175,15 @@ func New(cfg *config.CompressionConfig) (*Middleware, error) {
algorithm: algo,
}
for _, t := range m.types {
lower := strings.ToLower(t)
if base, found := strings.CutSuffix(lower, "/*"); found {
m.typesWildcardPrefix = append(m.typesWildcardPrefix, []byte(base))
} else {
m.typesBytes = append(m.typesBytes, []byte(lower))
}
}
// 初始化缓冲池
m.gzipPool = newGzipPool(cfg.Level)
m.brotliPool = newBrotliPool(cfg.Level)
@ -296,22 +309,20 @@ func (m *Middleware) Process(next fasthttp.RequestHandler) fasthttp.RequestHandl
// 返回值:
// - bool: 是否可压缩
func (m *Middleware) isCompressible(contentType []byte) bool {
// 移除 charset 等参数
ct := contentType
if idx := bytes.IndexByte(ct, ';'); idx >= 0 {
ct = ct[:idx]
}
ct = bytes.TrimSpace(ct)
for _, t := range m.types {
if bytes.Equal(bytes.ToLower([]byte(t)), ct) {
for _, t := range m.typesBytes {
if bytes.Equal(t, ct) {
return true
}
// 支持通配符匹配
if base, found := strings.CutSuffix(t, "/*"); found {
if bytes.HasPrefix(ct, []byte(base)) {
return true
}
}
for _, prefix := range m.typesWildcardPrefix {
if bytes.HasPrefix(ct, prefix) {
return true
}
}
return false