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

无法将tokio-postgres连接池传递给Axum处理器的问题

问题:无法将deadpool-postgres连接池传递给Axum处理器

作为Rust新手,我尝试用deadpool-postgres创建tokio-postgres连接池,并将其传递给Axum处理器来填充数据库表。连接池创建成功,但无法传递给处理器,出现编译错误。

相关代码

use axum::{
    extract::State,
    routing::{get, post},
    Router,
    http::{Response, StatusCode},
    extract::Form,
    response::{IntoResponse, Redirect}
};
use std::{convert::Infallible, fs, net::SocketAddr};
use tower_http::cors::{Any, CorsLayer};
use tokio_postgres::NoTls;
use deadpool_postgres::{Config, ManagerConfig, Pool, RecyclingMethod};

#[derive(Clone)]
struct AppState {
    db_pool: Pool
}

impl AppState {
    async fn make_pool() -> Self {
        let mut config = Config::new();
        config.user = Some("postgres".to_string());
        config.password = Some("postgres".to_string());
        config.dbname = Some("localhost".to_string());
        config.host = Some("localhost".to_string());
        config.port = Some(5432);
        config.manager = Some(ManagerConfig { 
            recycling_method: RecyclingMethod::Fast 
        });

        let pool = config.create_pool(None, NoTls).unwrap();
        pool.resize(15);

        AppState {
            db_pool: pool,
        }
    }
}

async fn handle_form(
    Form(data): Form<FormData>, 
    State(client): State<AppState>
) -> Result<Redirect, PoolError> {
    println!("->> handle_form__handler called");
    let conn = client.db_pool.get().await.unwrap();
    let values = (&data.nome, &data.cognome, &data.email);
    let query = "INSERT INTO users (nome, cognome, email) VALUES ($1, $2, $3)";
    
    if let Err(e) = conn.execute(query, &[&values.0, &values.1, &values.2])
        .await
        .map_err(|e| Into::<deadpool_postgres::PoolError>::into(e)) 
    {
        eprintln!("error executing query: {}", e);
        return Err(e.into());
    }

    Ok(Redirect::to("/form/success/"))
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let client = AppState::make_pool().await;
    let cors = CorsLayer::new().allow_origin(Any);

    let app = Router::new()
        .route("/", get(index_handler))
        .route("/about/", get(about_handler))
        .route("/form/", get(form_handler))
        .route("/form/submit-form/", post(handle_form))
        .route("/form/success/", get(success_handler))
        .with_state(client)
        .layer(cors);

    let addr = SocketAddr::from(([127, 0, 0, 1], 8000));
    println!("listening on {}", addr);
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await.unwrap();

    Ok(())
}

报错信息

最初报错

error[E0277]: the trait bound `fn(Form<FormData>, State<AppState>) -> impl Future<Output = Result<Redirect, deadpool::managed::errors::PoolError<tokio_postgres::Error>>> {handle_form}: Handler<_, _, _>` is not satisfied...

修改参数为State<AppState<Pool>>后的报错

error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied...

Cargo.toml依赖

[dependencies]
axum = "0.6.18"
tokio = { version = "1.28", features = ["full"] }
tokio-postgres = { version = "0.7.8", features = ["with-uuid-0_8"] }
tower-http = { version = "0.4.0", features = ["cors"] }
serde = { version = "1.0.162", features = ["derive"] }
deadpool-postgres = "0.10.5"

我还尝试用Extension替代State,但问题依旧。


解决方案

1. 补全缺失的FormData结构体

Axum的Form提取器需要目标结构体实现serde::Deserialize,添加以下定义:

#[derive(Debug, serde::Deserialize)]
struct FormData {
    nome: String,
    cognome: String,
    email: String,
}

2. 修正数据库配置错误

config.dbname被错误设置为"localhost",应该改为你的实际数据库名称:

config.dbname = Some("your_database_name".to_string()); // 替换为真实数据库名

3. 修正AppState::make_pool的错误处理

不要用unwrap,改用?传播错误,同时让方法返回Result:

impl AppState {
    async fn make_pool() -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
        let mut config = Config::new();
        config.user = Some("postgres".to_string());
        config.password = Some("postgres".to_string());
        config.dbname = Some("your_database_name".to_string());
        config.host = Some("localhost".to_string());
        config.port = Some(5432);
        config.manager = Some(ManagerConfig { 
            recycling_method: RecyclingMethod::Fast 
        });

        let pool = config.create_pool(None, NoTls)?;
        pool.resize(15);

        Ok(AppState { db_pool: pool })
    }
}

然后在main中调用时改为:

let client = AppState::make_pool().await?;

4. 修正处理器的返回类型与错误处理

Axum的Handler要求错误类型能转换为IntoResponse,同时避免使用unwrap:

use deadpool_postgres::PoolError;

async fn handle_form(
    Form(data): Form<FormData>,
    State(app_state): State<AppState>,
) -> Result<Redirect, impl IntoResponse> {
    println!("->> handle_form__handler called");
    
    // 获取连接池连接,错误时返回500响应
    let conn = app_state.db_pool.get().await.map_err(|e| {
        eprintln!("Failed to get connection from pool: {}", e);
        (StatusCode::INTERNAL_SERVER_ERROR, format!("Database connection error: {}", e))
    })?;

    let query = "INSERT INTO users (nome, cognome, email) VALUES ($1, $2, $3)";
    // 执行查询,错误时返回500响应
    conn.execute(query, &[&data.nome, &data.cognome, &data.email])
        .await
        .map_err(|e| {
            eprintln!("Error executing query: {}", e);
            (StatusCode::INTERNAL_SERVER_ERROR, format!("Query execution error: {}", e))
        })?;

    Ok(Redirect::to("/form/success/"))
}

5. 补全缺失的基础处理器

确保index_handler、about_handler等处理器已定义,示例:

async fn index_handler() -> impl IntoResponse {
    Response::builder()
        .status(StatusCode::OK)
        .body("Home Page".to_string())
        .unwrap()
}

async fn about_handler() -> impl IntoResponse {
    "About Page".to_string()
}

async fn form_handler() -> impl IntoResponse {
    r#"
    <form action="/form/submit-form/" method="post">
        <input type="text" name="nome" placeholder="Nome"><br>
        <input type="text" name="cognome" placeholder="Cognome"><br>
        <input type="email" name="email" placeholder="Email"><br>
        <button type="submit">Submit</button>
    </form>
    "#.to_string()
}

async fn success_handler() -> impl IntoResponse {
    "Form submitted successfully!".to_string()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 02:50:45