Skip to content

Commit c9f7871

Browse files
committed
feat(static): 为静态资源添加缓存控制策略
根据文件类型和文件名特征(如是否包含 hash)设置不同的 HTTP 缓存头, 以优化前端资源加载性能并确保 HTML 文件不被缓存。 - 移除 ScriptExecutor 中设置工作目录到 HOME 的逻辑 - 增加 strings 包导入 - 实现 setCacheHeaders 函数,支持: * HTML 文件禁用缓存 * 带 hash 的资源文件长期缓存 * JS/CSS 等资源缓存 1 小时 * 图片类资源缓存 1 天 * 其他资源默认缓存 1 小时
1 parent 659cd84 commit c9f7871

2 files changed

Lines changed: 71 additions & 5 deletions

File tree

internal/pkg/executor/executor.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,6 @@ func (e *ScriptExecutor) runCommand(cmd *exec.Cmd, scriptID string) (*ExecutionR
170170
// 继承当前进程的环境变量
171171
cmd.Env = os.Environ()
172172

173-
// 设置工作目录为用户的HOME目录,确保Git等工具能访问配置文件
174-
if homeDir, err := os.UserHomeDir(); err == nil {
175-
cmd.Dir = homeDir
176-
}
177-
178173
// 创建管道捕获输出
179174
stdout, err := cmd.StdoutPipe()
180175
if err != nil {

main.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"log"
99
"net/http"
1010
"os"
11+
"strings"
1112

1213
"hook-panel/internal/handlers"
1314
"hook-panel/internal/middleware"
@@ -61,6 +62,9 @@ func setupStaticFiles(r *gin.Engine) {
6162
contentType := getContentType(filePath)
6263
c.Header("Content-Type", contentType)
6364

65+
// 设置缓存头
66+
setCacheHeaders(c, filePath)
67+
6468
if stat, err := file.Stat(); err == nil {
6569
c.DataFromReader(http.StatusOK, stat.Size(), contentType, file, nil)
6670
return
@@ -124,6 +128,73 @@ func getContentType(filePath string) string {
124128
}
125129
}
126130

131+
// setCacheHeaders 根据文件类型设置缓存策略
132+
func setCacheHeaders(c *gin.Context, filePath string) {
133+
// HTML 文件不缓存,确保用户总是获取最新页面
134+
if strings.HasSuffix(filePath, ".html") {
135+
c.Header("Cache-Control", "no-cache, no-store, must-revalidate")
136+
c.Header("Pragma", "no-cache")
137+
c.Header("Expires", "0")
138+
return
139+
}
140+
141+
// 检查是否是带 hash 的资源文件(通常包含 8 位以上的十六进制字符)
142+
// 例如: app.a1b2c3d4.js, style.12345678.css
143+
isHashedFile := false
144+
fileName := filePath
145+
if lastSlash := strings.LastIndex(filePath, "/"); lastSlash != -1 {
146+
fileName = filePath[lastSlash+1:]
147+
}
148+
149+
// 简单判断:如果文件名中包含类似 hash 的模式
150+
if strings.Contains(fileName, ".") {
151+
parts := strings.Split(fileName, ".")
152+
for i := 1; i < len(parts)-1; i++ {
153+
if len(parts[i]) >= 8 && isHexString(parts[i]) {
154+
isHashedFile = true
155+
break
156+
}
157+
}
158+
}
159+
160+
// 对于带 hash 的资源文件,设置长期缓存(1年)
161+
if isHashedFile {
162+
c.Header("Cache-Control", "public, max-age=31536000, immutable")
163+
return
164+
}
165+
166+
// 对于 JS、CSS 等静态资源,设置较短的缓存(1小时)
167+
if strings.HasSuffix(filePath, ".js") || strings.HasSuffix(filePath, ".css") {
168+
c.Header("Cache-Control", "public, max-age=3600")
169+
return
170+
}
171+
172+
// 对于图片等静态资源,设置中等缓存(1天)
173+
if strings.HasSuffix(filePath, ".png") || strings.HasSuffix(filePath, ".jpg") ||
174+
strings.HasSuffix(filePath, ".jpeg") || strings.HasSuffix(filePath, ".gif") ||
175+
strings.HasSuffix(filePath, ".svg") || strings.HasSuffix(filePath, ".ico") ||
176+
strings.HasSuffix(filePath, ".webp") {
177+
c.Header("Cache-Control", "public, max-age=86400")
178+
return
179+
}
180+
181+
// 其他文件默认缓存1小时
182+
c.Header("Cache-Control", "public, max-age=3600")
183+
}
184+
185+
// isHexString 检查字符串是否为十六进制
186+
func isHexString(s string) bool {
187+
if len(s) == 0 {
188+
return false
189+
}
190+
for _, c := range s {
191+
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
192+
return false
193+
}
194+
}
195+
return true
196+
}
197+
127198
func main() {
128199
// 解析命令行参数
129200
var port string

0 commit comments

Comments
 (0)