UI files: ETag and revalidation on each load
The embedded UI was served without any cache header, so a browser or a proxy could keep an old app.js after an update (seen with the API token display). Each file now has an ETag (hash of its content, computed at startup); the page, app.js and style.css are sent with "no-cache", so each load costs a 304 without body until the next version. Fonts are cached for 30 days. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
367420961e
commit
3e703c8792
5 files changed
+89
-1
No files matched your search
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// staticFiles serves the embedded UI with an ETag per file (a hash of its
|
||||
// content, computed at startup). Pages, scripts and styles are revalidated on
|
||||
// every load ("no-cache"): an unchanged file costs a 304 without body, and the
|
||||
// files of a new version are always taken after an update. Fonts are kept for
|
||||
// 30 days.
|
||||
func staticFiles(static fs.FS) http.Handler {
|
||||
etags := map[string]string{}
|
||||
_ = fs.WalkDir(static, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil || d.IsDir() {
|
||||
return err
|
||||
}
|
||||
b, err := fs.ReadFile(static, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sum := sha256.Sum256(b)
|
||||
etags["/"+path] = `"` + hex.EncodeToString(sum[:8]) + `"`
|
||||
return nil
|
||||
})
|
||||
etags["/"] = etags["/index.html"]
|
||||
files := http.FileServer(http.FS(static))
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if tag, ok := etags[r.URL.Path]; ok {
|
||||
// http.FileServer answers If-None-Match with 304 from this header.
|
||||
w.Header().Set("ETag", tag)
|
||||
if strings.HasPrefix(r.URL.Path, "/fonts/") {
|
||||
w.Header().Set("Cache-Control", "public, max-age=2592000")
|
||||
} else {
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
}
|
||||
}
|
||||
files.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user