fix(server): send Cache-Control: no-cache for web assets

Returning players kept getting stale builds: after the /play canvas fix
deployed, the origin served the new play.html (verified — 8/8 cache-busted
requests) but browsers still rendered the old one even after a hard reload.

Cause: the server sets no Cache-Control on the web router. The HTML pages are
include_str!'d into the binary and the wasm-bindgen output (canvas.js,
canvas_bg.wasm, solitaire_wasm.*) uses fixed filenames that change in place on
every deploy, so browsers heuristically cache them indefinitely.

Add `Cache-Control: no-cache` in the security_headers middleware (which wraps
the web router). Browsers now revalidate before using a cached copy; ServeDir
supplies Last-Modified/ETag so unchanged assets still return a cheap 304, while
changed ones (a new deploy) are re-fetched. Stops the stale-build problem for
everyone going forward.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
funman300
2026-06-23 18:44:59 -07:00
parent 4850e9417e
commit 1b5dfa3e27
+8
View File
@@ -267,6 +267,14 @@ async fn security_headers(req: Request<axum::body::Body>, next: axum_middleware:
HeaderValue::from_static("nosniff"),
);
headers.insert("X-Frame-Options", HeaderValue::from_static("DENY"));
// Force revalidation of the web assets. The HTML pages are compiled into
// the binary via `include_str!` and the wasm-bindgen output (canvas.js,
// canvas_bg.wasm, solitaire_wasm.*) keeps fixed filenames that change in
// place on every deploy. Without this, browsers heuristically cache them
// and keep serving stale builds even after a hard reload. `no-cache` lets
// the browser keep a copy but revalidate first; ServeDir supplies
// Last-Modified/ETag so unchanged assets still return a cheap 304.
headers.insert("Cache-Control", HeaderValue::from_static("no-cache"));
res
}