fix: ensure domain-based index rewriting works for SPAs
Previously, SPA routes (e.g. `/dashboard`) bypassed custom index rewriting logic due to `actix_files` intercepting requests before the fallback handler. This hotfix reorders route registration and introduces explicit handling for unmatched paths and root (/) to support React-style routing with domain-specific index.html rewrites.
This commit is contained in:
parent
3b8360fa40
commit
85de86f835
3 changed files with 65 additions and 29 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -1267,7 +1267,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "servant"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"actix-files",
|
||||
"actix-web",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "servant"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
authors = ["Andrew G. <me@nuark.xyz>"]
|
||||
|
||||
|
|
|
|||
90
src/main.rs
90
src/main.rs
|
|
@ -1,9 +1,8 @@
|
|||
use std::path::Path;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use actix_files;
|
||||
use actix_web::{
|
||||
dev::{ServiceRequest, ServiceResponse}, middleware::Logger, App, HttpServer
|
||||
dev::{ServiceRequest, ServiceResponse}, middleware::Logger, web, App, HttpRequest, HttpServer
|
||||
};
|
||||
use clap::{arg, command, Parser};
|
||||
use env_logger::Env;
|
||||
|
|
@ -44,13 +43,18 @@ async fn main() -> std::io::Result<()> {
|
|||
|
||||
let args = ServantArgs::parse();
|
||||
|
||||
let bind_addr = format!("{}:{}", args.host, args.port);
|
||||
println!("Listening on http://{}", bind_addr);
|
||||
// Log configured rewrite rules
|
||||
if !args.rewrite_index.is_empty() {
|
||||
log::info!("Configured domain-to-index mappings:");
|
||||
for (domain, path) in &args.rewrite_index {
|
||||
log::info!(" {} => {}", domain, path);
|
||||
}
|
||||
} else {
|
||||
log::info!("No domain-to-index rewrite rules configured.");
|
||||
}
|
||||
|
||||
let index_path = Path::new(args.serve_dir.as_str())
|
||||
.join(args.index_file.as_str())
|
||||
.display()
|
||||
.to_string();
|
||||
let bind_addr = format!("{}:{}", args.host, args.port);
|
||||
log::info!("Listening on http://{}", bind_addr);
|
||||
|
||||
let mount_point = args.mount.clone();
|
||||
let serve_dir = args.serve_dir.clone();
|
||||
|
|
@ -68,29 +72,61 @@ async fn main() -> std::io::Result<()> {
|
|||
|
||||
App::new()
|
||||
.wrap(Logger::default())
|
||||
.route("/", web::get().to({
|
||||
let index_map = index_map.clone();
|
||||
let default_index = default_index.clone();
|
||||
let serve_dir = serve_dir.clone();
|
||||
move |req: HttpRequest| {
|
||||
let host = req
|
||||
.headers()
|
||||
.get("Host")
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.unwrap_or_default()
|
||||
.to_string();
|
||||
|
||||
let index_file = index_map
|
||||
.get(&host)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| format!("{}/{}", serve_dir, default_index));
|
||||
|
||||
log::info!("Custom '/' route: serving '{}' for domain '{}'", index_file, host);
|
||||
|
||||
async move {
|
||||
Ok::<_, actix_web::Error>(
|
||||
actix_files::NamedFile::open(index_file)?.into_response(&req),
|
||||
)
|
||||
}
|
||||
}
|
||||
}))
|
||||
.service(
|
||||
actix_files::Files::new(&mount_point, &serve_dir)
|
||||
.index_file(&default_index)
|
||||
.default_handler(move |req: ServiceRequest| {
|
||||
let (http_req, _payload) = req.into_parts();
|
||||
let host = http_req
|
||||
.headers()
|
||||
.get("Host")
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.unwrap_or_default();
|
||||
.use_last_modified(true),
|
||||
)
|
||||
.default_service(actix_web::dev::fn_service(move |req: ServiceRequest| {
|
||||
let (http_req, _payload) = req.into_parts();
|
||||
let host = http_req
|
||||
.headers()
|
||||
.get("Host")
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.unwrap_or_default()
|
||||
.to_string();
|
||||
|
||||
// Determine the index file based on the host
|
||||
let index_file = index_map
|
||||
.get(host)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| format!("{}/{}", serve_dir, default_index));
|
||||
log::info!("Request for domain: '{}'", host);
|
||||
|
||||
async move {
|
||||
let response = actix_files::NamedFile::open(index_file)?.into_response(&http_req);
|
||||
Ok(ServiceResponse::new(http_req, response))
|
||||
}
|
||||
}),
|
||||
)
|
||||
// Determine the index file based on the host
|
||||
let index_file = index_map
|
||||
.get(&host)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| format!("{}/{}", serve_dir, default_index));
|
||||
|
||||
// Log which index is being used for which domain
|
||||
log::info!("Serving file '{}' for domain '{}'", index_file, host);
|
||||
|
||||
async move {
|
||||
let response = actix_files::NamedFile::open(index_file)?.into_response(&http_req);
|
||||
Ok(ServiceResponse::new(http_req, response))
|
||||
}
|
||||
}))
|
||||
})
|
||||
.bind(bind_addr)?
|
||||
.run()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue