如何用axum与rust-embed托管并嵌入SPA文件及路由问题
解决方案:使用rust-embed + axum 托管嵌入式SPA
依赖配置
首先在Cargo.toml中添加所需依赖:
[dependencies] axum = "0.7" rust-embed = "8.0" tokio = { version = "1.0", features = ["full"] } mime_guess = "2.0"
嵌入静态文件
用rust-embed的宏指定SPA静态文件目录,编译时文件会被嵌入可执行文件:
use rust_embed::RustEmbed; #[derive(RustEmbed)] #[folder = "./app/static/"] // 替换为你的SPA静态文件实际路径 struct SpaAssets;
自定义SPA请求处理逻辑
编写统一的请求处理器,解决路由冲突和嵌套路由问题:
use axum::{ http::{StatusCode, HeaderValue}, response::{IntoResponse, Response}, }; use mime_guess::from_path; use std::path::PathBuf; async fn serve_spa(path: Option<PathBuf>) -> Response { // 默认请求根路径时返回index.html let target_path = path.unwrap_or_else(|| PathBuf::from("index.html")); // 尝试获取嵌入的文件 match SpaAssets::get(target_path.to_str().unwrap_or("index.html")) { Some(asset) => { // 根据文件后缀推断MIME类型,确保浏览器正确解析资源 let mime_type = from_path(&target_path) .first_or_octet_stream() .to_string(); let headers = [( axum::http::header::CONTENT_TYPE, HeaderValue::from_str(&mime_type).unwrap(), )]; (headers, asset.data).into_response() } None => { // 找不到对应文件时返回index.html,交由前端路由处理嵌套路径 match SpaAssets::get("index.html") { Some(index_asset) => { let headers = [( axum::http::header::CONTENT_TYPE, HeaderValue::from_static("text/html; charset=utf-8"), )]; (StatusCode::OK, headers, index_asset.data).into_response() } None => (StatusCode::NOT_FOUND, "Missing index.html").into_response() } } } }
配置Axum路由
将所有GET请求导向自定义处理器,同时可以优先添加API路由避免被SPA逻辑拦截:
#[tokio::main] async fn main() { let app = axum::Router::new() // 先注册API路由(如果有),确保优先匹配 // .route("/api/user", axum::routing::get(get_user)) // 匹配所有路径,处理SPA资源和嵌套路由 .route("/*path", axum::routing::get(serve_spa)); let addr = ([127, 0, 0, 1], 3000).into(); println!("Server running on http://{}", addr); axum::Server::bind(&addr) .serve(app.into_make_service()) .await .unwrap(); }
方案说明
- 解决嵌套路由404问题:当用户刷新
/home/customers这类虚拟路由时,处理器找不到对应文件,自动返回index.html,前端路由会接管路径渲染对应页面。 - 解决路由冲突问题:不再单独注册
/index.html路由,所有请求通过统一处理器判断文件是否存在,避免了路由冲突 panic。 - 嵌入文件到可执行文件:
rust-embed在编译阶段将静态文件打包进可执行文件,部署时无需携带额外静态资源目录。
注意事项
- 确保SPA资源的引用路径为根路径(如
/app.js而非./app.js),否则嵌入后无法正确加载。 - API路由必须放在
/*path路由之前,Axum会按路由定义顺序匹配,避免API请求被SPA处理器拦截。 - 静态文件修改后需要重新编译,因为
rust-embed是编译时嵌入文件。
内容的提问来源于stack exchange,提问作者Fred Hors
相关产品推荐
相关产品推荐

