You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Actix/Diesel API无法响应Postman请求 寻求排查解决

问题描述

我基于Actix与Diesel开发的Rust API代码可正常编译,执行cargo run后程序能正常运行并输出调试打印信息,但无法响应任何Postman请求。尝试向http://127.0.0.1:8080/create_book发送POST请求时,Postman报错:Requested application data is not configured correctly. View/enable debug logs for more details.,且接口处理函数开头的println语句从未执行。

相关代码

main.rs

use actix_web::{web, App, HttpServer};
use diesel::r2d2::{ConnectionManager, Pool};
use diesel::sqlite::SqliteConnection;
use dotenvy::dotenv;

#[path = "api/books/books_handlers.rs"]
mod books_handlers;
#[path = "api/books_relationships/books_relationships_handlers.rs"]
mod books_relationships_handlers;
mod models;
mod routes;
mod schema;
mod logger;

#[actix_rt::main]
async fn main() -> std::io::Result<()> {

    // Load .env file and set initialization variables
    dotenv().ok();
    std::env::set_var("RUST_LOG", "actix_web=debug");
    let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");


    // Create db connection pool with SQLite
    let manager = ConnectionManager::<SqliteConnection>::new(database_url);
    let pool: Pool<ConnectionManager<SqliteConnection>> = r2d2::Pool::builder()
        .build(manager)
        .expect("Failed to create pool.");

    // Start HTTP server and register routes
    println!("Starting server at http://localhost:8080");
    HttpServer::new(move || {
        App::new()
            .app_data(pool.clone())
            // Book class
            .route("/create_book", web::post().to(books_handlers::create_book_handler))
            .route("/list_books", web::get().to(books_handlers::list_books_handler))
            .route("/get_book/{id}", web::post().to(books_handlers::read_book_by_id_handler))
            .route("/update_book/{id}", web::put().to(books_handlers::update_book_handler))
            .route("/delete_book/{id}", web::delete().to(books_handlers::delete_book_handler))
            // BookRelationships class
            .route("/create_book_relationship", web::post().to(books_relationships_handlers::create_book_relationship_handler))
            .route("/list_book_relationships", web::get().to(books_relationships_handlers::list_books_handler))
            .route("/get_book_relationship/{id}", web::post().to(books_relationships_handlers::read_book_by_id_handler))
            .route("/update_book_relationship/{id}", web::put().to(books_relationships_handlers::update_book_handler))
            .route("/delete_book_relationship/{id}", web::delete().to(books_relationships_handlers::delete_book_handler))

        })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

create_book_handler

pub async fn create_book_handler(book_data: web::Json<Book>, pool: web::Data<DbPool>) -> HttpResponse {
    println!("create_book_handler: {:#?}", book_data);  // <-- 从未执行
    let result = books_dao::create_book(book_data, pool).await;
    match result {
        Ok(book) => {
            println!("create_book_handler, OK. Book: {:#?}", book);
            HttpResponse::Ok()
            .content_type(ContentType::json())
            .json(&book)
        },
        Err(err) => {
            println!("create_book_handler, ERROR: {:#?}", err);
            log(LogType::Error, err.to_string());
            HttpResponse::InternalServerError()
                .content_type(ContentType::json())
                .body("{err: 'Unable to insert book into database'}")
        }
    }
}

create_book DAO函数

pub async fn create_book(book: web::Json<Book>, pool: web::Data<DbPool>) -> Result<usize, Error> {
    let mut conn = pool
        .get()
        .expect("Failed to get database connection from pool");

    diesel::insert_into(books::table)
        .values(book.into_inner())
        .execute(&mut conn)
}
问题排查与解决

请求未进入处理函数,说明请求在到达业务逻辑前就被拦截,以下是核心问题点和修复方案:

1. 缺失日志初始化,无法获取Actix调试信息

你设置了RUST_LOG环境变量,但未初始化日志框架,导致Actix无法输出请求处理的详细错误日志,无法定位拦截原因。

  • 修复:在main函数开头添加日志初始化代码(需先在Cargo.toml添加env_logger依赖):
    env_logger::init();
    
    启动后即可看到路由匹配、请求解析等环节的详细日志。

2. 请求体解析失败(最可能原因)

处理函数接收web::Json<Book>,若Postman请求不符合要求,Actix会在进入处理函数前直接返回错误:

  • 检查Postman设置:确保请求头Content-Type为application/json
  • 验证JSON格式:发送的JSON字段需与Book结构体完全匹配(包括字段名大小写、数据类型,比如字符串需加引号,数字不能加引号)
  • 简化测试:临时简化Book结构体为仅含必填字段,排除复杂类型解析问题

3. 数据库连接池类型不匹配

需确保DbPool类型定义与处理函数中web::Data<DbPool>的类型完全一致:

  • 正确定义:
    type DbPool = Pool<ConnectionManager<SqliteConnection>>;
    
    类型不匹配会导致Actix无法从App数据中提取连接池,进而拦截请求。

4. 同步Diesel操作阻塞异步线程

Diesel的数据库操作是同步的,直接在Actix异步线程中执行会阻塞事件循环,虽不会导致请求无法进入处理函数,但会导致后续响应卡住:

  • 修复:用Actix的web::block将同步操作放到线程池执行:
    pub async fn create_book(book: web::Json<Book>, pool: web::Data<DbPool>) -> Result<usize, Error> {
        let book_inner = book.into_inner();
        let pool_clone = pool.clone();
        // 在线程池执行阻塞操作
        web::block(move || {
            let mut conn = pool_clone.get().expect("Failed to get database connection from pool");
            diesel::insert_into(books::table)
                .values(book_inner)
                .execute(&mut conn)
        }).await?
    }
    

5. 路由干扰排查

可临时注释其他路由,仅保留/create_book的POST路由,排除其他路由注册错误的干扰;也可替换为极简处理函数测试:

pub async fn test_handler() -> HttpResponse {
    println!("Test handler called!");
    HttpResponse::Ok().body("Hello")
}

若该函数能正常响应,说明问题出在原处理函数的参数解析或业务逻辑上。

内容的提问来源于stack exchange,提问作者Zerok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 02:35:26