如何从 Rust 中的 gRPC 服务器处理程序干净地返回错误?

问题描述 投票:0回答:1

是否有一种相当简单的方法来处理 Rust 中 gRPC 服务器处理函数的错误转换?我是 Rust 新手,所以也许这是不可能的,但我确实看到很多东西表明错误类型之间的转换非常常见。

例如:

我有以下处理程序:

use tonic::{Request, Response, Status}
use stuff::{DoStuffRequest, stuff_server::Stuff}

#[derive(Default)]
pub struct MyStuff {} 

#[tonic::async_trait]
impl Stuff for MyStuff {
    async fn do_stuff(&self, request: Request<DoStuffRequest>) ->
        Response<DoStuffResponse, Status>
    {
        let data = ...; // get what should be valid json
        let jsonstr = String::from_utf8(data)?;
        let json = serde_json::from_str(&jsonstr)?;

        Ok(Response::new(DoStuffResponse{...}))
    }
}

我想要的是

?
from_utf8
from_str
中获取任何错误并将它们转换为
Status
,这样我就不必使用大的
match
表达式来转换错误。

我正在使用

thiserror
创建中间错误类型,然后从我的错误类型转换为
Status
,但 rust 似乎不想转换它。

#[derive(Error, Debug)]
enum MyStuffError {
    #[error("UTF-8 conversion error: {0}")]
    Utf8Error(#[from] std::string::FromUtf8Error),
    #[error("JSON error: {0}")]
    JsonError(#[from] serde_json::Error)
}

impl From<MyStuffError> for Status {
    fn from(error: MyStuffError) -> Self {
        Status::unknown(error.to_string())
    }
}

我得到:

error[E0277]: `?` couldn't convert the error to `Status`
  --> src/server.rs:58:48
   |
58 |     let jsonstr = String::from_utf8(data)?;
   |                                         ^ the trait `From<FromUtf8Error>` is not implemented for `Status`, which is required by `Result<tonic::Response<DoStuffResponse>, Status>: FromResidual<Result<Infallible, FromUtf8Error>>`
   |
   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
   = help: the following other types implement trait `From<T>`:
             <Status as From<MyStuffError>>
             <Status as From<h2::error::Error>>
             <Status as From<std::io::Error>>
   = note: required for `Result<tonic::Response<DoStuffResponse>, Status>` to implement `FromResidual<Result<Infallible, FromUtf8Error>>`
rust grpc
1个回答
0
投票
仅当存在从

?

E
 的直接转换时,
Status
才能转换错误。它不能做
E
E1
Status
,因为它不知道选择哪个
E1
(毕竟可能有几种类型可以去那里)。一种解决方案是使用
map_err
指定正确的类型,例如:

#[tonic::async_trait]
impl Stuff for MyStuff {
    async fn do_stuff(&self, request: Request<DoStuffRequest>) ->
        Result<Response<DoStuffResponse>, Status>
    {
        let data = ...; // get what should be valid json
        let jsonstr = String::from_utf8 (data).map_err (MyStuffError::from)?;
        let json = serde_json::from_str (&jsonstr).map_err (MyStuffError::from)?;

        Ok (Response::new (DoStuffResponse {…}))
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.