mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-21 00:00:14 +02:00
examples: fix using_serve_dir_with_assets_fallback to not expose assets at root (#3762)
Co-authored-by: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
7a37cdd00a
commit
a480d71f6d
Generated
+1
@@ -1611,6 +1611,7 @@ name = "example-static-file-server"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"http-body-util",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-http",
|
||||
|
||||
@@ -8,6 +8,9 @@ publish = false
|
||||
axum = { path = "../../axum" }
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
tower = { version = "0.5.2", features = ["util"] }
|
||||
tower-http = { version = "0.6.1", features = ["fs", "trace"] }
|
||||
tower-http = { version = "0.6.1", features = ["fs", "set-status", "trace"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
||||
[dev-dependencies]
|
||||
http-body-util = "0.1.0"
|
||||
|
||||
@@ -11,6 +11,7 @@ use std::net::SocketAddr;
|
||||
use tower::ServiceExt;
|
||||
use tower_http::{
|
||||
services::{ServeDir, ServeFile},
|
||||
set_status::SetStatus,
|
||||
trace::TraceLayer,
|
||||
};
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
@@ -45,13 +46,18 @@ fn using_serve_dir() -> Router {
|
||||
fn using_serve_dir_with_assets_fallback() -> Router {
|
||||
// `ServeDir` allows setting a fallback if an asset is not found
|
||||
// so with this `GET /assets/doesnt-exist.jpg` will return `index.html`
|
||||
// rather than a 404
|
||||
let serve_dir = ServeDir::new("assets").not_found_service(ServeFile::new("assets/index.html"));
|
||||
// rather than a 404.
|
||||
// The `fallback_service` ensures that all other paths (the standard
|
||||
// SPA pattern) also return `index.html`. We wrap it in `SetStatus` so
|
||||
// the response uses 404 instead of 200 -- the path wasn't found, the SPA
|
||||
// just handles routing client-side.
|
||||
let index_html = SetStatus::new(ServeFile::new("assets/index.html"), StatusCode::NOT_FOUND);
|
||||
let serve_dir = ServeDir::new("assets").not_found_service(index_html.clone());
|
||||
|
||||
Router::new()
|
||||
.route("/foo", get(|| async { "Hi from /foo" }))
|
||||
.nest_service("/assets", serve_dir.clone())
|
||||
.fallback_service(serve_dir)
|
||||
.nest_service("/assets", serve_dir)
|
||||
.fallback_service(index_html)
|
||||
}
|
||||
|
||||
fn using_serve_dir_only_from_root_via_fallback() -> Router {
|
||||
@@ -107,6 +113,9 @@ fn using_serve_file_from_a_route() -> Router {
|
||||
Router::new().route_service("/foo", ServeFile::new("assets/index.html"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
async fn serve(app: Router, port: u16) {
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], port));
|
||||
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
use super::using_serve_dir_with_assets_fallback;
|
||||
use axum::{body::Body, http::Request, http::StatusCode};
|
||||
use http_body_util::BodyExt;
|
||||
use tower::ServiceExt;
|
||||
|
||||
const INDEX_HTML_CONTENT: &str = include_str!("../assets/index.html");
|
||||
|
||||
// `/script.js` at the root is not an asset under `/assets`, so it falls through to the SPA
|
||||
// fallback. The fallback serves `index.html` with a 404 status -- the path wasn't found, but
|
||||
// the SPA handles routing client-side.
|
||||
#[tokio::test]
|
||||
async fn assets_not_served_at_root() {
|
||||
let app = using_serve_dir_with_assets_fallback();
|
||||
let response = app
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.uri("/script.js")
|
||||
.body(Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(response.status(), StatusCode::NOT_FOUND);
|
||||
let body = response.into_body().collect().await.unwrap().to_bytes();
|
||||
let body_str = String::from_utf8(body.to_vec()).unwrap();
|
||||
assert_eq!(body_str, INDEX_HTML_CONTENT);
|
||||
}
|
||||
Reference in New Issue
Block a user