fix(server): scope no-cache to HTML pages (fix web-e2e cycle gate) #102
@@ -203,7 +203,12 @@ fn build_router_inner(state: AppState, rate_limit: bool) -> Router {
|
||||
// and the wasm-bindgen-generated `web/pkg/`). The HTML page is the
|
||||
// same regardless of `:id` — it reads the path from `location` in JS
|
||||
// and fetches the replay JSON from `/api/replays/:id`.
|
||||
let web = Router::new()
|
||||
// HTML pages are `include_str!`'d into the binary and change on every
|
||||
// deploy, so they get `Cache-Control: no-cache` (always revalidate). The
|
||||
// `/web` + `/assets` static files keep ServeDir's default Last-Modified
|
||||
// caching — applying no-cache to *those* too made the e2e cycle gate's 240
|
||||
// page reloads recompile the wasm each time and time out.
|
||||
let html_pages = Router::new()
|
||||
.route(
|
||||
"/",
|
||||
get(|| async { Html(include_str!("../web/home.html")) }),
|
||||
@@ -233,6 +238,10 @@ fn build_router_inner(state: AppState, rate_limit: bool) -> Router {
|
||||
"/replays",
|
||||
get(|| async { Html(include_str!("../web/replays.html")) }),
|
||||
)
|
||||
.layer(axum_middleware::from_fn(no_cache_headers));
|
||||
|
||||
let web = Router::new()
|
||||
.merge(html_pages)
|
||||
.nest_service("/web", ServeDir::new("solitaire_server/web"))
|
||||
.nest_service("/assets", ServeDir::new("assets"))
|
||||
.layer(axum_middleware::from_fn(security_headers));
|
||||
@@ -267,14 +276,18 @@ 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
|
||||
}
|
||||
|
||||
/// Adds `Cache-Control: no-cache` so the browser always revalidates before
|
||||
/// using a cached copy. Scoped to the `include_str!` HTML pages (which change
|
||||
/// on every deploy and have no validators) — not the ServeDir static assets,
|
||||
/// which keep normal Last-Modified caching so repeated page loads can reuse the
|
||||
/// already-downloaded/compiled wasm.
|
||||
async fn no_cache_headers(req: Request<axum::body::Body>, next: axum_middleware::Next) -> Response {
|
||||
let mut res = next.run(req).await;
|
||||
res.headers_mut()
|
||||
.insert("Cache-Control", HeaderValue::from_static("no-cache"));
|
||||
res
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user