Actix-Web中服务注册顺序为何重要?代码示例解析
问题描述
原始可正常运行的代码片段:
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 }
当交换静态文件服务与上传请求处理服务的注册顺序后:
.service(actix_files::Files::new("/", "./src/static").index_file("index.html")) .service(web::resource("/upload").route(web::post().to(upload_handler::upload_handler)))
发送POST请求到http://127.0.0.1:8080/upload时会触发错误:
POST http://127.0.0.1:8080/upload 405 (Method Not Allowed)
原因分析
1. Actix-Web的路由匹配规则
Actix-Web中服务的注册顺序直接决定了请求的匹配优先级:先注册的服务会先尝试处理请求,一旦某个服务匹配成功并处理了请求,后续的服务就不会再被触发。
2. actix_files::Files服务的行为
当使用Files::new("/", "./src/static")时,这个服务会匹配所有以/开头的请求(也就是所有请求),它的处理逻辑是:
- 首先检查请求路径对应的静态文件是否存在于指定目录中
- 如果文件不存在,会尝试返回配置的
index_file(这里是index.html) - 但默认情况下,
Files服务仅支持GET和HEAD两种请求方法,对其他方法(比如POST)会直接返回405 Method Not Allowed
3. 错误产生的具体过程
当把Files服务注册在/upload的POST路由之前时:
- 发送
POST /upload请求后,会先被Files服务捕获 Files服务找不到./src/static/upload这个静态文件,于是尝试返回index.html,但因为请求方法是POST,不在它支持的范围内,直接返回405错误- 此时后面的
/uploadPOST路由根本没有机会被匹配到,自然无法处理上传请求
而正确的注册顺序中,/upload的POST路由先被注册,POST /upload请求会被该路由优先匹配并处理,其他请求才会落入Files服务处理静态资源,因此不会出现问题。
内容的提问来源于stack exchange,提问作者fehd
相关产品推荐
相关产品推荐

