无法将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
相关产品推荐
相关产品推荐

