mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
dev day #79
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// AssetCacheControl sets optimal Cache-Control headers for static assets served by this server.
|
||||
// It only affects GET requests for well-known static prefixes and does not override
|
||||
// cache headers explicitly set by handlers downstream (they can still modify after c.Next if needed).
|
||||
func AssetCacheControl() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// Only apply to GET requests
|
||||
if c.Request.Method == http.MethodGet {
|
||||
p := c.Request.URL.Path
|
||||
lower := strings.ToLower(p)
|
||||
switch {
|
||||
// Specific: YouTube channel static cache can be cached longer (content changes infrequently)
|
||||
case strings.HasPrefix(lower, "/cache/prefetch/") && strings.HasSuffix(lower, "youtube_channel.json"):
|
||||
c.Header("Cache-Control", "public, max-age=3600") // 1 hour
|
||||
case strings.HasPrefix(lower, "/dist/"):
|
||||
// Fingerprinted build assets should be cached for a year and immutable
|
||||
c.Header("Cache-Control", "public, max-age=31536000, immutable")
|
||||
case strings.HasPrefix(lower, "/uploads/"):
|
||||
// User uploads: cache for a week; allow clients to revalidate if replaced
|
||||
// Heuristic: if file name appears fingerprinted (e.g., .<hash>.ext), use longer cache
|
||||
base := filepath.Base(lower)
|
||||
if looksFingerprinted(base) {
|
||||
c.Header("Cache-Control", "public, max-age=31536000, immutable")
|
||||
} else {
|
||||
c.Header("Cache-Control", "public, max-age=604800") // 7 days
|
||||
}
|
||||
case strings.HasPrefix(lower, "/cache/"):
|
||||
// Prefetched JSON and other generated cache files: short to medium cache
|
||||
c.Header("Cache-Control", "public, max-age=300") // 5 minutes
|
||||
}
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// looksFingerprinted checks if a filename contains a long hex-like segment before the extension
|
||||
// e.g. logo.7eacd9f0bfa04928a9b6936140168f58.png
|
||||
func looksFingerprinted(name string) bool {
|
||||
dot := strings.LastIndexByte(name, '.')
|
||||
if dot <= 0 || dot >= len(name)-1 {
|
||||
return false
|
||||
}
|
||||
core := name[:dot]
|
||||
// Find final segment after last dot/underscore/hyphen in core
|
||||
lastSep := strings.LastIndexAny(core, "._-")
|
||||
if lastSep < 0 || lastSep+1 >= len(core) {
|
||||
return false
|
||||
}
|
||||
seg := core[lastSep+1:]
|
||||
if len(seg) < 16 { // require at least 16 chars to treat as a hash
|
||||
return false
|
||||
}
|
||||
// hex-like check
|
||||
for i := 0; i < len(seg); i++ {
|
||||
ch := seg[i]
|
||||
if !((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f')) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user