diff --git a/src/proxy.rs b/src/proxy.rs index a73042a..1b80575 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -22,6 +22,16 @@ pub async fn isr_handler(State(state): State>, req: Request) -> Re let path = uri.path(); let query = uri.query(); + // Redirect trailing slashes to non-trailing (except root) + if path.len() > 1 && path.ends_with('/') { + let normalized = path.trim_end_matches('/'); + let redirect_uri = match query { + Some(q) => format!("{normalized}?{q}"), + None => normalized.to_string(), + }; + return axum::response::Redirect::permanent(&redirect_uri).into_response(); + } + if method != axum::http::Method::GET && method != axum::http::Method::HEAD { tracing::warn!(method = %method, path = %path, "Non-GET/HEAD request to non-API route"); diff --git a/web/src/routes/+layout.server.ts b/web/src/routes/+layout.server.ts index 25c7c26..775c7c8 100644 --- a/web/src/routes/+layout.server.ts +++ b/web/src/routes/+layout.server.ts @@ -4,6 +4,8 @@ import { apiFetch } from "$lib/api.server"; import type { SiteSettings } from "$lib/admin-types"; import { building } from "$app/environment"; +export const trailingSlash = "never"; + const DEFAULT_SETTINGS: SiteSettings = { identity: { siteTitle: "xevion.dev",