rust-embed:嵌入静态资源
·
rust-embed是一个用于将资源文件嵌入到可执行程序的库,例如当我们使用Vue开发了前端应用后,可以将前端编译后直接嵌入到后端服务中,这样无需单独的前端环境也可运行。
首先在Cargo.toml中添加rust-embed的依赖。
[dependencies]
rust-embed = "8.7.2"
然后定义一个Asset,表示需要嵌入的资源。
use rust_embed::Embed;
#[derive(Embed)]
#[folder = "web/dist/"]
struct Asset;
注意folder的路径默认为当前项目的根目录,即Cargo.toml所在目录(如果是子模块,则是子模块的根目录),也支持绝对路径,或者环境变量。
当使用环境变量作为路径时,需要启用interpolate-folder-path功能,支持自定义环境变量,可以在cargo build时传入。
我的后端框架使用的是Rocket,所以定义一个get端点,用于访问资源。
use rocket::http::ContentType;
use rocket::http::uri::Segments;
use rocket::http::uri::fmt::Path;
#[get("/<path..>", rank = 500)]
pub(crate) async fn web(path: Segments<'_, Path>) -> Option<(ContentType, Vec<u8>)> {
let path = path.collect::<Vec<_>>().join("/");
let index = Some((ContentType::HTML, Asset::get("index.html")?.data.into()));
if path == "" {
return index;
}
let ext = path.split('.').last()?;
if let Some(embedded_file) = Asset::get(&path) {
let data: Vec<u8> = embedded_file.data.into();
Some((ContentType::from_extension(ext)?, data))
} else {
index
}
}
将这个端点挂载到Rocket的路由上即可:
#[cfg(not(debug_assertions))]
{
builder = builder.mount("/", routes![web::web]);
}
仅在release模式下启用这个端点,是因为在开发时,前端需要实时更新,此时不需要嵌入。
需要注意的点:
• rank值设置尽量大一点,rank越大,优先级越低,这样可以防止和其他路由冲突,
• 当找不到资源时不要返回错误,而是仍然返回index,因为Vue是单页面应用,需要由浏览器按照访问路径执行JS渲染到对应的页面,所以返回index即可。
• 返回时需要指定响应的Content-Type,可以从文件后缀中获取。
通过以上几步,就可以在将前端集成到后端服务中啦。
最近弄了一个公众号,每天准时分享Rust相关知识。每天学一点点,Rust也很简单。点击下方即可打开二维码,扫一扫关注一下🥰。
更多推荐


所有评论(0)