2

I'm struggling with actix-web 2.0 framework of rust. I want my rust server to serve the my index.html file but most of the help available is of older versions and hence a lot has changed in newer version. I tried following code but it's not working for actix-web 2.0. Please suggest some working solution in actix-web 2.0.

use actix_files::NamedFile;
use actix_web::{HttpRequest, Result};
async fn index(req: HttpRequest) -> Result<NamedFile> {
    Ok(NamedFile::open(path_to_file)?)
}

By trying the code given in the answer I could serve a single html file but it is unable to load the linked JavaScript file. I have tried the following approach suggested in https://actix.rs/docs/static-files/ to serve the directory.

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    dotenv::dotenv().ok();
    std::env::set_var("RUST_LOG", "actix_web=debug");
    let database_url = std::env::var("DATABASE_URL").expect("set DATABASE_URL");

    // create db connection pool
    let manager = ConnectionManager::<PgConnection>::new(database_url);
    let pool: Pool = r2d2::Pool::builder()
        .build(manager)
        .expect("Failed to create pool.");
    
    //Serving the Registration and sign-in page
    async fn index(_req: HttpRequest) -> Result<NamedFile> {
        let path: PathBuf = "./static/index.html".parse().unwrap();
        Ok(NamedFile::open(path)?)
    }

    // Start http server
    HttpServer::new(move || {
        App::new()
            .data(pool.clone())
            .service(fs::Files::new("/static", ".").show_files_listing())
            .route("/", web::get().to(index))
            .route("/users", web::get().to(handler::get_users))
            .route("/users/{id}", web::get().to(handler::get_user_by_id))
            .route("/users", web::post().to(handler::add_user))
            .route("/users/{id}", web::delete().to(handler::delete_user))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

Above is my main method. In browser console I'm still getting the error that unable to load the Registration.js resource. Following is my folder structure:

-migrations
-src
  -main.rs
  -handler.rs
  -errors.rs
  -models.rs
  -schema.rs
-static
 -index.html
 -Registration.js
-target
Cargo.toml
.env
Cargo.lock
diesel.toml

I have already built the backend with DB integration and it is working fine as checked by curl commands and now I'm trying to build front end and as first step trying to serve static files.

E_net4
  • 27,810
  • 13
  • 101
  • 139
Fatima Nasim
  • 31
  • 1
  • 8
  • What is happening when you try your existing code? In what way is it not doing what you want? – harmic Aug 30 '20 at 07:32
  • @harmic i have edited my question . Have a look if you could find something . – Fatima Nasim Aug 31 '20 at 13:23
  • The second argument for `fs::Files::new` is the directory you want to serve. `"."` would be the current directory - which would be whatever directory you are running from, not the 'static' dir. Try putting the full path to the static dir. – harmic Aug 31 '20 at 21:45
  • @yes thanks for explaining. i find that out. I'm also putting a good example of usage in my question. – Fatima Nasim Aug 31 '20 at 21:58

3 Answers3

8

I am not sure what problem you're facing since the description is not detailed, however, I ran the default example and it is working.

use actix_files::NamedFile;
use actix_web::{HttpRequest, Result};
use std::path::PathBuf;

/// https://actix.rs/docs/static-files/
async fn index(_req: HttpRequest) -> Result<NamedFile> {
    let path: PathBuf = "./files/index.html".parse().unwrap();
    Ok(NamedFile::open(path)?)
}

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    use actix_web::{web, App, HttpServer};

    HttpServer::new(|| App::new().route("/", web::get().to(index)))
        .bind("127.0.0.1:8088")?
        .run()
        .await
}

project structure

- files/index.html
- src/index.rs
- cargo.toml

dependencies

[dependencies]
actix-web = "2.0.0"
actix-files = "0.2.2"
actix-rt = "1.1.1"
E_net4
  • 27,810
  • 13
  • 101
  • 139
cperez08
  • 709
  • 4
  • 9
  • Thanks it worked for me. was missing the pathBuf and it saved me . – Fatima Nasim Aug 30 '20 at 20:16
  • can you answer another question? my html file is serving but it seems that linked JS is not being served. Do you have any suggestion – Fatima Nasim Aug 30 '20 at 23:46
  • check here https://actix.rs/docs/static-files/ the Directory part so you can serve everything in the directory including the CSS, JS or whatever files you have there – cperez08 Aug 31 '20 at 06:25
  • I'm still unable to load the other resources. I have edited my post. please have a look if you could find what i'm doing wrong? – Fatima Nasim Aug 31 '20 at 13:22
  • The 2023 way is here: https://docs.rs/actix-files/latest/actix_files/struct.NamedFile.html – cloudsurfin Aug 31 '23 at 17:27
5

If you want to really embed resources into executable you can use https://crates.io/crates/actix-web-static-files.

It uses build.rs to prepare resources and later you can just have single executable without dependencies.

As extra it support npm based builds out of the box.

Basically I am an author of this crate. There are versions both for 2.x and 3.x versions of actix-web.

3

Please see the below code that it works for the whole subdirectories:

main.rs

use actix_files as fs;
use actix_web::{App, HttpServer};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new().service(
            fs::Files::new("/", "./public")
                .show_files_listing()
                .index_file("index.html")
                .use_last_modified(true),
        )
    })
    .bind("0.0.0.0:8000")?
    .run()
    .await
}

Cargo.toml

[package]
name = "actixminimal"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

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

It perform file serving very fast ever I'd tried.

In this case, you can create a "public" or you can use your own "static" folder (then change your code related to the folder name) or you can export the static files from your web framework. I use GatsbyJS and I use deploy parameter to "public" folder. I share it on my github. https://github.com/openmymai/actixminimal.git

sirisakc
  • 892
  • 2
  • 15
  • 30
  • 1
    If you are planning to serve a react app you might want to consider adding a `default_handler` to funnel all non-existing paths back to index.html so that refreshing the browser works with your react router: ```.default_handler(fn_service(|req: ServiceRequest| async { let (req, _) = req.into_parts(); let file = NamedFile::open_async(format!("{}/{}", get_files_path().unwrap(), STATIC_INDEX)).await?; let res = file.into_response(&req); Ok(ServiceResponse::new(req, res)) }))``` – iganev Mar 29 '23 at 22:34