diff --git a/src/web/routes.rs b/src/web/routes.rs index 1f1bd5ca..448da579 100644 --- a/src/web/routes.rs +++ b/src/web/routes.rs @@ -4,9 +4,11 @@ use axum::{ routing::{delete, put}, }; use axum::{ + http::StatusCode, middleware, + response::IntoResponse, routing::{any, get, patch, post}, - Router, + Json, Router, }; use std::sync::Arc; use tower_http::{ @@ -363,6 +365,7 @@ pub fn create_router(state: Arc) -> Router { .merge(protected_routes) .merge(stream_routes) .merge(upload_routes) + .fallback(api_not_found) .layer(middleware::from_fn_with_state( state.clone(), auth_middleware, @@ -384,3 +387,14 @@ pub fn create_router(state: Arc) -> Router { None => main_router, } } + +async fn api_not_found() -> impl IntoResponse { + ( + StatusCode::NOT_FOUND, + Json(super::ErrorResponse { + success: false, + code: None, + message: "Not Found".to_string(), + }), + ) +} diff --git a/src/web/static_files.rs b/src/web/static_files.rs index 1ac99dd6..24c8bfbe 100644 --- a/src/web/static_files.rs +++ b/src/web/static_files.rs @@ -48,7 +48,9 @@ where { Router::new() .route("/", get(index_handler)) - .route("/{*path}", get(static_handler)) + // GET-only fallback: a `/{*path}` wildcard would shadow fallbacks + // nested under other routers (e.g. the /api 404 handler) in axum 0.8. + .fallback_service(get(static_handler)) } async fn index_handler() -> Response { @@ -63,33 +65,25 @@ async fn static_handler(uri: Uri) -> Response { } if !path.contains('.') { + // SPA fallback: extensionless paths are frontend routes. if let Some(response) = try_serve_file("index.html") { return response; } } + not_found_response() +} + +fn not_found_response() -> Response { Response::builder() - .status(StatusCode::OK) + .status(StatusCode::NOT_FOUND) .header(header::CONTENT_TYPE, "text/html; charset=utf-8") - .body(Body::from(placeholder_html())) + .body(Body::from(not_found_html())) .unwrap() } fn serve_file(path: &str) -> Response { - try_serve_file(path).unwrap_or_else(|| { - if path == "index.html" { - Response::builder() - .status(StatusCode::OK) - .header(header::CONTENT_TYPE, "text/html; charset=utf-8") - .body(Body::from(placeholder_html())) - .unwrap() - } else { - Response::builder() - .status(StatusCode::NOT_FOUND) - .body(Body::from("Not Found")) - .unwrap() - } - }) + try_serve_file(path).unwrap_or_else(|| not_found_response()) } fn try_serve_file(path: &str) -> Option> { @@ -149,41 +143,23 @@ fn static_response(path: &str, data: Vec) -> Response { .unwrap() } -pub fn placeholder_html() -> String { +pub fn not_found_html() -> String { r#" - + - - - One-KVM + 404 Not Found -
-

One-KVM

-

Frontend not built yet.

-

Please build the frontend or access the API directly.

-
v{{VERSION}}
-
+

404 Not Found

"# - .replace("{{VERSION}}", env!("CARGO_PKG_VERSION")) + .to_string() }