Sending Files

Salvo provides several ways to send files:

NamedFile

Salvo offers salvo::fs::NamedFile for efficiently sending files to clients. Instead of loading entire files into memory, it streams partial content based on the request's Range header.

In fact, Response::send_file is simply a convenience wrapper around NamedFile. For more granular control over file sending, use NamedFileBuilder.

Create a NamedFileBuilder via NamedFile::builder:

#[handler]
async fn send_file(req: &mut Request, res: &mut Response) {
    let builder = NamedFile::builder("/file/to/path");
}

Configure settings before sending the file:

#[handler]
async fn send_file(req: &mut Request, res: &mut Response) {
    NamedFile::builder("/file/to/path").attached_name("image.png").send(req.headers(), res).await;
}

Serve Static

Middleware for serving static files or embedded resources.

  • StaticDir supports serving from local directories. Multiple directories can be specified as fallback paths. For example:
main.rs
Cargo.toml
static-dir-list/src/main.rs
use salvo::prelude::*;
use salvo::serve_static::StaticDir;

#[tokio::main]
async fn main() {
tracing_subscriber::fmt().init();

let router = Router::with_path("{*path}").get(
StaticDir::new([
    "static-dir-list/static/boy",
    "static-dir-list/static/girl",
    "static/boy",
    "static/girl",
])
.include_dot_files(false)
.defaults("index.html")
.auto_list(true),
);

let acceptor = TcpListener::new("0.0.0.0:5800").bind().await;
Server::new(acceptor).serve(router).await;
}

If a file isn't found in the first directory, the system will check subsequent directories.

  • Includes support for rust-embed integration:
main.rs
Cargo.toml
static-embed-files/src/main.rs
use rust_embed::RustEmbed;
use salvo::prelude::*;
use salvo::serve_static::static_embed;

#[derive(RustEmbed)]
#[folder = "static"]
struct Assets;

#[tokio::main]
async fn main() {
tracing_subscriber::fmt().init();

let router = Router::with_path("{*path}").get(static_embed::<Assets>().fallback("index.html"));

let acceptor = TcpListener::new("0.0.0.0:5800").bind().await;
Server::new(acceptor).serve(router).await;
}

The with_fallback method specifies a fallback file when the requested resource isn't found, which is particularly useful for single-page applications.