Rust Actix Web中如何将业务Result转换为HttpResponse返回值
问题原因
你遇到的编译错误核心是:Rust标准库不会为Result<A, B>到Result<C, D>提供默认的From/Into实现,哪怕A可以转换为C、B可以转换为D,也需要你显式处理Result的Ok和Err两个分支。你之前为自定义错误实现ResponseError、为返回结构体实现转换的方向是正确的,问题出在直接对整个Result调用into()的写法。
解决步骤
步骤1:确认自定义错误正确实现ResponseError trait
按照如下代码实现即可,可根据业务需要调整对应错误的HTTP状态码和返回内容:
use actix_web::{error::ResponseError, http::StatusCode, HttpResponse}; use derive_more::{Display, Error}; #[derive(Debug, Display, Error)] pub enum CredentialServiceError { NoCredentialFound, ErrorOnGeneratingJWT, } impl ResponseError for CredentialServiceError { fn status_code(&self) -> StatusCode { match self { // 账号密码错误返回401 CredentialServiceError::NoCredentialFound => StatusCode::UNAUTHORIZED, // 服务内部错误返回500 CredentialServiceError::ErrorOnGeneratingJWT => StatusCode::INTERNAL_SERVER_ERROR, } } fn error_response(&self) -> HttpResponse { HttpResponse::build(self.status_code()) .body(self.to_string()) } }
步骤2:修改接口handler逻辑
不需要单独为LoginResponse实现Into<HttpResponse>,直接使用Actix内置的JSON序列化方法即可,有两种常用写法可选:
写法1:使用?提前处理错误(更简洁,推荐)
use actix_web::{web, HttpResponse, Result}; async fn login( request_body: web::Json<LoginRequest>, credential_service: web::Data<CredentialService> ) -> Result<HttpResponse> { let request_body = request_body.0; // ?会自动把实现了ResponseError的自定义错误转为actix_web::Error let jwt = credential_service.login(request_body.username, request_body.password)?; let response = LoginResponse { jwt }; // 直接构造JSON响应 Ok(HttpResponse::Ok().json(response)) }
写法2:链式调用分别处理Ok和Err分支
use actix_web::{web, HttpResponse, Result}; async fn login( request_body: web::Json<LoginRequest>, credential_service: web::Data<CredentialService> ) -> Result<HttpResponse> { let request_body = request_body.0; credential_service.login(request_body.username, request_body.password) .map(|jwt| LoginResponse { jwt }) .map(|resp| HttpResponse::Ok().json(resp)) // 显式将自定义错误转为actix_web::Error .map_err(|e| e.into()) }
内容的提问来源于stack exchange,提问作者allevo
相关产品推荐
相关产品推荐

