use actix_web::{HttpResponse, ResponseError}; use serde::Serialize; use thiserror::Error; /// 统一错误响应体(不泄露内部细节) #[derive(Serialize)] pub struct ErrorResponse { pub code: u32, pub message: String, } /// 应用错误类型 #[derive(Debug, Error)] pub enum AppError { #[error("参数验证失败: {0}")] Validation(String), #[error("未授权访问")] Unauthorized, #[error("资源不存在")] NotFound, #[error("钱包已存在")] WalletAlreadyExists, #[error("余额不足")] InsufficientBalance, #[error("手续费不足")] InsufficientFee, #[error("内部服务错误")] Internal, #[error("数据库错误")] Database, } impl ResponseError for AppError { fn error_response(&self) -> HttpResponse { // 注意:所有错误响应都使用通用描述,不泄露内部实现细节 match self { AppError::Validation(msg) => HttpResponse::BadRequest().json(ErrorResponse { code: 4001, message: msg.clone(), }), AppError::Unauthorized => HttpResponse::Unauthorized().json(ErrorResponse { code: 4010, message: "未授权访问".to_string(), }), AppError::NotFound => HttpResponse::NotFound().json(ErrorResponse { code: 4040, message: "资源不存在".to_string(), }), AppError::WalletAlreadyExists => HttpResponse::Conflict().json(ErrorResponse { code: 4091, message: "该用户钱包已存在".to_string(), }), AppError::InsufficientBalance => HttpResponse::BadRequest().json(ErrorResponse { code: 4002, message: "余额不足".to_string(), }), AppError::InsufficientFee => HttpResponse::BadRequest().json(ErrorResponse { code: 4003, message: "XIC手续费余额不足".to_string(), }), // 内部错误统一返回500,不暴露细节 AppError::Internal | AppError::Database => { HttpResponse::InternalServerError().json(ErrorResponse { code: 5000, message: "服务暂时不可用,请稍后重试".to_string(), }) } } } }