Sending Files

Salvo can send files in several ways:

NamedFile

Salvo provides salvo::fs::NamedFile, which can be used to efficiently send files to clients. It does not load the entire file into memory; instead, it reads and sends only the portions requested by the client based on the Range header.

In practice, using Response::send_file is a simplified way to utilize NamedFile. If you need more control over file delivery, you can use NamedFileBuilder.

You can create a NamedFileBuilder via NamedFile::builder:

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

After configuring the builder, you can send 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 files.

  • StaticDir provides support for serving static files from local directories. You can pass a list of multiple directories as arguments. For example:
main.rs
Cargo.toml
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:8698").bind().await;
    Server::new(acceptor).serve(router).await;
}

If a file is not found in the first directory, it will be searched for in the second directory.

  • Provides support for rust-embed. For example:
main.rs
Cargo.toml
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:8698").bind().await;
    Server::new(acceptor).serve(router).await;
}

The with_fallback method allows you to specify a fallback file to serve when the requested file is not found. This is particularly useful for single-page applications (SPAs).