refactor(handler,middleware,server): 增强预压缩配置灵活性

- NewGzipStatic 增加 precompressedExtensions 参数,支持自定义预压缩扩展名
- SetGzipStatic 分离源文件扩展名和预压缩扩展名参数
- 更新相关测试用例

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
xfy 2026-04-22 13:35:03 +08:00
parent 91d67ad384
commit 2bdc8f3b3b
5 changed files with 36 additions and 27 deletions

View File

@ -164,18 +164,19 @@ func (h *StaticHandler) SetFileCache(fc *cache.FileCache) {
// SetGzipStatic 设置预压缩文件支持。
//
// 启用后,对于匹配扩展名的请求,优先发送 .gz 预压缩文件。
// 启用后,对于匹配扩展名的请求,优先发送预压缩文件。
//
// 参数:
// - enabled: 是否启用预压缩支持
// - extensions: 需要支持预压缩的文件扩展名列表(如 [".html", ".css", ".js"]
// - extensions: 支持预压缩的源文件扩展名列表(如 [".html", ".css", ".js"]),为空使用默认值
// - precompressedExtensions: 预压缩文件扩展名列表(如 [".br", ".gz"]),为空使用默认值
//
// 使用示例:
//
// handler.SetGzipStatic(true, []string{".html", ".css", ".js"})
func (h *StaticHandler) SetGzipStatic(enabled bool, extensions []string) {
// handler.SetGzipStatic(true, nil, []string{".gz", ".br"})
func (h *StaticHandler) SetGzipStatic(enabled bool, extensions, precompressedExtensions []string) {
if enabled {
h.gzipStatic = compression.NewGzipStatic(true, h.root, extensions)
h.gzipStatic = compression.NewGzipStatic(true, h.root, extensions, precompressedExtensions)
}
}

View File

@ -449,13 +449,13 @@ func TestStaticHandler_SetGzipStatic(t *testing.T) {
handler := NewStaticHandler("/var/www", "/", nil, false)
// 启用 gzip
handler.SetGzipStatic(true, []string{".gz", ".gzip"})
handler.SetGzipStatic(true, nil, []string{".gz", ".gzip"})
if handler.gzipStatic == nil {
t.Error("Expected gzipStatic to be non-nil")
}
// 禁用 gzip
handler.SetGzipStatic(false, nil)
handler.SetGzipStatic(false, nil, nil)
// gzipStatic 保持不变SetGzipStatic 只在 enabled=true 时设置)
}
@ -525,7 +525,7 @@ func TestStaticHandler_Handle_Precompressed(t *testing.T) {
}
handler := NewStaticHandler(tmpDir, "/", nil, false)
handler.SetGzipStatic(true, []string{".gz"})
handler.SetGzipStatic(true, nil, []string{".gz"})
ctx := &fasthttp.RequestCtx{}
ctx.Request.SetRequestURI("/test.txt")

View File

@ -55,19 +55,23 @@ type GzipStatic struct {
// 参数:
// - enabled: 是否启用预压缩支持
// - root: 静态文件根目录路径
// - extensions: 支持预压缩的文件扩展名列表,为空则使用默认值
// - extensions: 支持预压缩的源文件扩展名列表(如 .html, .css为空则使用默认值
// - precompressedExtensions: 预压缩文件扩展名列表(如 .br, .gz为空则使用默认值
//
// 返回值:
// - *GzipStatic: 创建的预压缩文件处理器
func NewGzipStatic(enabled bool, root string, extensions []string) *GzipStatic {
func NewGzipStatic(enabled bool, root string, extensions, precompressedExtensions []string) *GzipStatic {
if len(extensions) == 0 {
extensions = []string{".html", ".css", ".js", ".json", ".xml", ".svg", ".txt"}
}
if len(precompressedExtensions) == 0 {
precompressedExtensions = []string{".br", ".gz"}
}
return &GzipStatic{
enabled: enabled,
root: root,
extensions: extensions,
precompressedExtensions: []string{".br", ".gz"},
precompressedExtensions: precompressedExtensions,
}
}

View File

@ -35,7 +35,7 @@ func TestGzipStaticServeFile_BrotliPriority(t *testing.T) {
t.Fatalf("创建 .gz 文件失败: %v", err)
}
g := NewGzipStatic(true, tmpDir, nil)
g := NewGzipStatic(true, tmpDir, nil, nil)
tests := []struct {
acceptEncoding string
@ -119,7 +119,7 @@ func TestGzipStaticServeFile_GzipFallback(t *testing.T) {
t.Fatalf("创建 .gz 文件失败: %v", err)
}
g := NewGzipStatic(true, tmpDir, nil)
g := NewGzipStatic(true, tmpDir, nil, nil)
tests := []struct {
acceptEncoding string
@ -177,7 +177,7 @@ func TestGzipStaticServeFile_AcceptEncodingParsing(t *testing.T) {
t.Fatalf("创建 .br 文件失败: %v", err)
}
g := NewGzipStatic(true, tmpDir, nil)
g := NewGzipStatic(true, tmpDir, nil, nil)
tests := []struct {
name string
@ -241,7 +241,7 @@ func TestGzipStaticServeFile_Disabled(t *testing.T) {
}
// 禁用的 GzipStatic
g := NewGzipStatic(false, tmpDir, nil)
g := NewGzipStatic(false, tmpDir, nil, nil)
ctx := &fasthttp.RequestCtx{}
ctx.Request.Header.Set("Accept-Encoding", "br")
@ -263,7 +263,7 @@ func TestGzipStaticServeFile_InvalidExtension(t *testing.T) {
t.Fatalf("创建 .br 文件失败: %v", err)
}
g := NewGzipStatic(true, tmpDir, nil)
g := NewGzipStatic(true, tmpDir, nil, nil)
ctx := &fasthttp.RequestCtx{}
ctx.Request.Header.Set("Accept-Encoding", "br")
@ -285,7 +285,7 @@ func TestGzipStaticServeFile_PathTraversal(t *testing.T) {
t.Fatalf("创建 .br 文件失败: %v", err)
}
g := NewGzipStatic(true, tmpDir, nil)
g := NewGzipStatic(true, tmpDir, nil, nil)
ctx := &fasthttp.RequestCtx{}
ctx.Request.Header.Set("Accept-Encoding", "br")
@ -308,7 +308,7 @@ func TestGzipStaticServeFile_VaryHeader(t *testing.T) {
t.Fatalf("创建 .br 文件失败: %v", err)
}
g := NewGzipStatic(true, tmpDir, nil)
g := NewGzipStatic(true, tmpDir, nil, nil)
ctx := &fasthttp.RequestCtx{}
ctx.Request.Header.Set("Accept-Encoding", "br")
@ -323,7 +323,7 @@ func TestGzipStaticServeFile_VaryHeader(t *testing.T) {
// TestNewGzipStatic_DefaultExtensions 测试默认扩展名
func TestNewGzipStatic_DefaultExtensions(t *testing.T) {
g := NewGzipStatic(true, "/tmp", nil)
g := NewGzipStatic(true, "/tmp", nil, nil)
expected := []string{".html", ".css", ".js", ".json", ".xml", ".svg", ".txt"}
got := g.Extensions()
@ -342,7 +342,7 @@ func TestNewGzipStatic_DefaultExtensions(t *testing.T) {
// TestNewGzipStatic_CustomExtensions 测试自定义扩展名
func TestNewGzipStatic_CustomExtensions(t *testing.T) {
custom := []string{".custom", ".ext"}
g := NewGzipStatic(true, "/tmp", custom)
g := NewGzipStatic(true, "/tmp", custom, nil)
got := g.Extensions()
if len(got) != 2 || got[0] != ".custom" || got[1] != ".ext" {
@ -352,12 +352,12 @@ func TestNewGzipStatic_CustomExtensions(t *testing.T) {
// TestGzipStatic_Enabled 测试 Enabled 方法
func TestGzipStatic_Enabled(t *testing.T) {
g1 := NewGzipStatic(true, "/tmp", nil)
g1 := NewGzipStatic(true, "/tmp", nil, nil)
if !g1.Enabled() {
t.Error("Enabled() = false, want true")
}
g2 := NewGzipStatic(false, "/tmp", nil)
g2 := NewGzipStatic(false, "/tmp", nil, nil)
if g2.Enabled() {
t.Error("Enabled() = true, want false")
}
@ -366,7 +366,7 @@ func TestGzipStatic_Enabled(t *testing.T) {
// TestDefaultExtensions 测试默认扩展名(通过 NewGzipStatic 间接测试)
func TestDefaultExtensions(t *testing.T) {
expected := []string{".html", ".css", ".js", ".json", ".xml", ".svg", ".txt"}
g := NewGzipStatic(true, "/tmp", nil)
g := NewGzipStatic(true, "/tmp", nil, nil)
got := g.Extensions()
if len(got) != len(expected) {
@ -462,7 +462,7 @@ func TestTryServeFile(t *testing.T) {
ctx := &fasthttp.RequestCtx{}
ctx.Request.Header.Set("Accept-Encoding", "br")
g := NewGzipStatic(true, tmpDir, nil)
g := NewGzipStatic(true, tmpDir, nil, nil)
served := g.ServeFile(ctx, "test.js")
if !served {
@ -477,7 +477,7 @@ func TestTryServeFile(t *testing.T) {
// TestGzipStatic_PrecompressedExtensions 测试预压缩扩展名优先级
func TestGzipStatic_PrecompressedExtensions(t *testing.T) {
g := NewGzipStatic(true, "/tmp", nil)
g := NewGzipStatic(true, "/tmp", nil, nil)
// 验证默认预压缩扩展名顺序
expected := []string{".br", ".gz"}

View File

@ -1083,7 +1083,9 @@ func (s *Server) registerStaticHandlersWithLocationEngine(cfg *config.ServerConf
staticHandler.SetCacheTTL(5 * time.Second)
}
if cfg.Compression.GzipStatic {
staticHandler.SetGzipStatic(true, cfg.Compression.GzipStaticExtensions)
// extensions: 源文件类型,为空使用默认值
// GzipStaticExtensions: 预压缩文件扩展名(如 .br, .gz
staticHandler.SetGzipStatic(true, nil, cfg.Compression.GzipStaticExtensions)
}
// 设置符号链接安全检查
@ -1446,7 +1448,9 @@ func (s *Server) registerStaticHandlers(router *handler.Router, cfg *config.Serv
staticHandler.SetCacheTTL(5 * time.Second)
}
if cfg.Compression.GzipStatic {
staticHandler.SetGzipStatic(true, cfg.Compression.GzipStaticExtensions)
// extensions: 源文件类型,为空使用默认值
// GzipStaticExtensions: 预压缩文件扩展名(如 .br, .gz
staticHandler.SetGzipStatic(true, nil, cfg.Compression.GzipStaticExtensions)
}
// 设置符号链接安全检查