无法将 tokio-postgres 池连接传递给 Axum 处理程序

问题描述 投票:0回答:1

我是 Rust 新手。 我正在尝试创建一个到处理程序的 tokio-postgres 连接池,它应该使用该连接来填充数据库表。 我使用 deadpool-postgres ,它似乎创建了池。 问题是我无法将池传递给处理程序。

这是与问题相关的代码:

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!("->>\thandle_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
   --> src/main.rs:85:43
    |
85  |         .route("/form/submit-form/", post(handle_form))
    |                                      ---- ^^^^^^^^^^^ the trait `Handler<_, _, _>` is not implemented for fn item `fn(Form<FormData>, State<AppState>) -> impl Future<Output = Result<Redirect, deadpool::managed::errors::PoolError<tokio_postgres::Error>>> {handle_form}`
    |                                      |
    |                                      required by a bound introduced by this call
    |
    = help: the following other types implement trait `Handler<T, S, B>`:
              <Layered<L, H, T, S, B, B2> as Handler<T, S, B2>>
              <MethodRouter<S, B> as Handler<(), S, B>>
note: required by a bound in `post`
   --> /home/bontxa/.cargo/registry/src/github.com-1ecc6299db9ec823/axum-0.6.18/src/routing/method_routing.rs:407:1
    |
407 | top_level_handler_fn!(post, POST);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `post`
    = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)

要修复此错误,我更改此行:

async fn handle_form(Form(data): Form<FormData>, State(client): State<AppState>) -> Result<Redirect, PoolError>

在:

async fn handle_form(Form(data): Form<FormData>, State(client): State<AppState<Pool>>) -> Result<Redirect, PoolError>

但是现在新的错误是:

error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
  --> src/main.rs:57:71
   |
57 | async fn handle_form(Form(data): Form<FormData>, State(client): State<AppState<Pool>>) -> Result<Redirect, PoolError> {
   |                                                                       ^^^^^^^^------ help: remove these generics
   |                                                                       |
   |                                                                       expected 0 generic arguments
   |
note: struct defined here, with 0 generic parameters
  --> src/main.rs:26:8
   |
26 | struct AppState {
   |        ^^^^^^^^

这是我的 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”,但情况是一样的。

rust connection-pooling rust-tokio rust-axum tokio-postgres
1个回答
1
投票

deadpool::managed::errors::PoolError
应该转换为其他错误类型,可以转换为响应。

use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::Json;
use serde_json::json;
use thiserror::Error;

/// # ApiError
#[derive(Debug, Error)]
pub enum ApiError {
    #[error(transparent)]
    DbError(#[from] sea_orm::DbErr),
    #[error("not found")]
    NotFound,
}

impl IntoResponse for ApiError {
    fn into_response(self) -> Response {
        let status = match self {
            ApiError::NotFound => StatusCode::NOT_FOUND,
            _ => StatusCode::BAD_REQUEST,
        };
        let body = Json(json!({
            "error": self.to_string(),
        }));
        (status, body).into_response()
    }
}

完整演示代码

© www.soinside.com 2019 - 2024. All rights reserved.