From 4cf3f4e252f0b5846bc07ac4d36f128c0cabcdbf Mon Sep 17 00:00:00 2001 From: mofeng-git Date: Tue, 22 Sep 2026 21:42:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(web):=20=E5=AE=8C=E5=96=84=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=20404=20=E5=93=8D=E5=BA=94=E5=B9=B6=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=20/api=20=E6=9C=AA=E5=8C=B9=E9=85=8D=E8=B7=AF=E7=94=B1?= =?UTF-8?q?=E8=A2=AB=E9=9D=99=E6=80=81=E5=85=9C=E5=BA=95=E9=81=AE=E8=94=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 静态资源缺失时返回 404 HTML,移除"前端未构建"占位页 - /api 未匹配路由返回统一的 404 JSON - 静态兜底由 /{*path} 改为 fallback_service,避免在 axum 0.8 下遮蔽嵌套 /api 的 fallback 并导致鉴权被绕过 --- src/web/routes.rs | 16 ++++++++++- src/web/static_files.rs | 62 +++++++++++++---------------------------- 2 files changed, 34 insertions(+), 44 deletions(-) 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() }