rust

how to make the rust actix web return static file that open in browser directly


I am using actix-web to provide the static pdf file preview, this is the rust code look like:

use actix_web::{error::ErrorBadRequest, web, App, HttpRequest, HttpServer, Responder};
use actix_files::{Files, NamedFile};
use mime::Mime;

async fn namefile(req: HttpRequest) -> impl Responder {
    let pdf_file_path = "/Users/xiaoqiangjiang/source/reddwarf/backend/rust-learn/doc/sample.pdf";
    match NamedFile::open(&pdf_file_path) {
        Ok(file) => {
            let content_type: Mime = "application/pdf".parse().unwrap();
            return NamedFile::set_content_type(file, content_type).into_response(&req);
        }
        Err(e) => {
            return ErrorBadRequest("File not Found").into();
        }
    }
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/namefile", web::get().to(namefile))
            .service(Files::new("/static", "./static").show_files_listing())
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

this is the Cargo.toml:

[package]
name = "rust-learn"
version = "0.1.0"
edition = "2018"

[dependencies]
actix-web = "4"
actix-files = "0.6.2"
mime = "0.3.17"

[profile.release]
debug = true

but when I access the pdf in google chrome using url http://localhost:8080/namefile, it popup the download window. Is it possible to preview the pdf in google chrome browser? do not popup the download window.


Solution

  • By default, the Content-Disposition for application/pdf is set to attachment, causing the browser to download.

    You need to manually change it to inline for the browser to display it directly:

    use actix_files::{Files, NamedFile};
    use actix_web::{
        error::ErrorBadRequest,
        http::header::{ContentDisposition, DispositionType},
        web, App, HttpRequest, HttpServer, Responder,
    };
    use mime::Mime;
    
    async fn namefile(req: HttpRequest) -> impl Responder {
        let pdf_file_path = "dummy.pdf";
        match NamedFile::open(&pdf_file_path) {
            Ok(file) => {
                let content_type: Mime = "application/pdf".parse().unwrap();
                NamedFile::set_content_type(file, content_type)
                    .set_content_disposition(ContentDisposition {
                        disposition: DispositionType::Inline,
                        parameters: Vec::new(),
                    })
                    .into_response(&req)
            }
            Err(e) => {
                return ErrorBadRequest("File not Found").into();
            }
        }
    }
    
    #[actix_web::main]
    async fn main() -> std::io::Result<()> {
        HttpServer::new(|| {
            App::new()
                .route("/namefile", web::get().to(namefile))
                .service(Files::new("/static", "./static").show_files_listing())
        })
        .bind("127.0.0.1:8080")?
        .run()
        .await
    }