Send File

Salvo can send files in a number of ways:

NamedFile

Salvo provides salvo::::NamedFile, which can be used to efficiently send files to the client. It does not load all files into the cache, but loads part of the content according to the requested Range sent to the client.

Actually, passing Response::send_file is just a simplified way of using NamedFile, if you need more control over the sent file, you can use NamedFileBuilder.

A NamedFileBuilder can be created via NamedFile::builder:

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

You can do some settings, and then 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 that serves static files or embedded files as a service.

  • StaticDir provides support for static local folders. It can take a list of multiple folders as an argument. For example:

    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([
                "examples/static-dir-list/static/boy",
                "examples/static-dir-list/static/girl",
            ])
            .defaults("index.html")
            .auto_list(true),
        );
    
        let acceptor = TcpListener::new("127.0.0.1:5800").bind().await;
        Server::new(acceptor).serve(router).await;
    }
    
    [package]
    name = "example-static-dir-list"
    version = "0.1.0"
    edition = "2021"
    publish = false
    
    
    [dependencies]
    salvo = { workspace = true, features = ["serve-static"] }
    tokio = { version = "1", features = ["macros"] }
    tracing = "0.1"
    tracing-subscriber = "0.3"
    

    If the corresponding file is not found in the first folder, it will be found in the second folder.

  • Provided support for rust-embed, such as:

    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("127.0.0.1:5800").bind().await;
        Server::new(acceptor).serve(router).await;
    }
    
    [package]
    name = "example-static-embed-files"
    version = "0.1.0"
    edition = "2021"
    publish = false
    
    
    [dependencies]
    rust-embed = { workspace = true }
    salvo = { workspace = true, features = ["serve-static"] }
    tokio = { version = "1", features = ["macros"] }
    tracing = "0.1"
    tracing-subscriber = "0.3"
    

    with_fallback can be set to use the file set here instead when the file cannot be found. This is still useful for some single-page website applications.