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