rustactix-web

How does order of services matter in Actix-Web?


Given the following code snippet:

mod handlers;
mod utils;

use actix_files;
use actix_web::{middleware::Logger, web, App, HttpServer};
use handlers::upload_handler;
use std::path::Path;
use tokio::fs;

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    env_logger::init_from_env(env_logger::Env::new().default_filter_or("debug"));

    if !Path::new("./upload").exists() {
        fs::create_dir("./upload").await?;
    }

    HttpServer::new(|| {
        App::new()
            .wrap(Logger::default())
            .service(web::resource("/upload").route(web::post().to(upload_handler::upload_handler)))
            .service(actix_files::Files::new("/", "./src/static").index_file("index.html"))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

Why does swapping the lines serving the static file index.html and handling the upload break the code? With the lines in the following order

.service(actix_files::Files::new("/", "./src/static").index_file("index.html"))
.service(web::resource("/upload").route(web::post().to(upload_handler::upload_handler)))

uploading a file (i.e., creating a POST request) will result in a error:

POST http://127.0.0.1:8080/upload 405 (Method Not Allowed)

Solution

  • The documentation for actix-files' Files says:

    Implementation Notes

    If the mount path is set as the root path /, services registered after this one will be inaccessible. Register more specific handlers and services first.


    In general, .service()s are processed in the order added to your App/Scope. In this case actix-files is at the root and vacuously handles all paths, and thus would handle the /upload path as well and not give the resource a chance.