use actix_web::{web, get, HttpResponse, Responder}; use sqlx::postgres::PgPool; use serde::Serialize; #[derive(Serialize)] pub struct HealthResponse { pub status: String, pub database: String, #[serde(skip_serializing_if = "Option::is_none")] pub error: Option, #[serde(skip_serializing_if = "Option::is_none")] pub hint: Option, } #[get("/health")] pub async fn health_check(pool: web::Data) -> impl Responder { match sqlx::query("SELECT 1").fetch_one(pool.get_ref()).await { Ok(_) => { HttpResponse::Ok().json(HealthResponse { status: "ok".to_string(), database: "connected".to_string(), error: None, hint: None, }) } Err(e) => { let err_str = e.to_string(); let (error_msg, hint_msg) = if err_str.contains("connection refused") { ( "无法连接到数据库".to_string(), "请检查数据库服务是否运行".to_string(), ) } else if err_str.contains("Connection timed out") { ( "数据库连接超时".to_string(), "请检查网络连接".to_string(), ) } else if err_str.contains("does not exist") { ("数据库不存在".to_string(), "请检查数据库配置".to_string()) } else if err_str.contains("28P01") { ( "数据库认证失败".to_string(), "用户名或密码错误".to_string(), ) } else { ( "数据库连接失败".to_string(), "请查看服务器日志获取详细信息".to_string(), ) }; tracing::error!("健康检查失败: {:?}", e); HttpResponse::ServiceUnavailable().json(HealthResponse { status: "error".to_string(), database: "disconnected".to_string(), error: Some(error_msg), hint: Some(hint_msg), }) } } }