From fc586d4aceab3c73349a40b7305c1ade1083f260 Mon Sep 17 00:00:00 2001 From: xfy Date: Thu, 30 Apr 2026 13:29:26 +0800 Subject: [PATCH] fix(handler): normalize root path to fix relative path performance When root is configured as a relative path (e.g., "./lib/site/"), filepath.Join normalizes it to "lib/site/" but the original value was stored in h.root. This caused strings.TrimPrefix in serveFile to fail, resulting in incorrect path calculations for GzipStatic. The bug caused every request to attempt opening a non-existent precompressed file path like "lib/site/lib/site/index.html.gz", adding an extra failed os.Stat call per request and reducing performance by ~50%. Fix by normalizing root with filepath.Clean in NewStaticHandler and SetRoot to ensure TrimPrefix works correctly. Co-Authored-By: Claude Opus 4.7 --- internal/handler/static.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/internal/handler/static.go b/internal/handler/static.go index 2c35c2d..ee76b52 100644 --- a/internal/handler/static.go +++ b/internal/handler/static.go @@ -82,8 +82,14 @@ type StaticHandler struct { // // handler := handler.NewStaticHandler("/var/www", "/", []string{"index.html"}, true) func NewStaticHandler(root, pathPrefix string, index []string, useSendfile bool) *StaticHandler { + // 规范化 root 路径,确保 TrimPrefix 能正确工作 + // filepath.Clean 会去掉 ./ 并规范化路径分隔符 + cleanRoot := filepath.Clean(root) + if !strings.HasSuffix(cleanRoot, string(filepath.Separator)) { + cleanRoot += string(filepath.Separator) + } return &StaticHandler{ - root: root, + root: cleanRoot, pathPrefix: pathPrefix, index: index, useSendfile: useSendfile, @@ -136,8 +142,13 @@ func (h *StaticHandler) SetAlias(alias string) { // 参数: // - root: 静态文件根目录 func (h *StaticHandler) SetRoot(root string) { - h.root = root - if root != "" { + // 规范化 root 路径 + cleanRoot := filepath.Clean(root) + if !strings.HasSuffix(cleanRoot, string(filepath.Separator)) { + cleanRoot += string(filepath.Separator) + } + h.root = cleanRoot + if cleanRoot != "" { h.alias = "" } }