【问题标题】:Creating a hyper service with custom error type创建具有自定义错误类型的超级服务
【发布时间】:2018-10-31 09:40:14
【问题描述】:

我正在尝试使用 hyper 创建一个 REST 服务器。对于强大的错误处理,我希望服务返回一个包含超、柴油和其他错误的自定义错误类型的未来。不幸的是,hyper::Response 似乎硬编码了错误类型为hyper::error::Error 的流,这与我为我的服务定义的错误类型冲突。我看到了几个可能的解决方案:

  1. 通过修改hyper::Response 让我的服务返回我的自定义错误类型,这似乎很难。

  2. hyper::error::Error 中包装非超错误。这看起来很老套。

  3. 别的东西。看来我错过了执行此操作的“正确”方法。

以下代码显示了我想我想做的事情:

extern crate diesel;
extern crate futures;
extern crate hyper;

use futures::future::{ok, Future};
use hyper::StatusCode;
use hyper::server::{Request, Response, Service};

fn main() {
    let address = "127.0.0.1:8080".parse().unwrap();
    let server = hyper::server::Http::new()
        .bind(&address, move || Ok(ApiService {}))
        .unwrap();
    server.run().unwrap();
}

pub struct ApiService;

impl Service for ApiService {
    type Request = Request;
    type Response = Response;
    type Error = Error;
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn call(&self, request: Request) -> Self::Future {
        Box::new(ok(Response::new().with_status(StatusCode::Ok)))
    }
}

#[derive(Debug)]
pub enum Error {
    Request(hyper::Error),
    DatabaseResult(diesel::result::Error),
    DatabaseConnection(diesel::ConnectionError),
    Other(String),
}

// omitted impl of Display, std::error::Error for brevity

此代码导致编译器错误,我认为这是因为bind 函数要求响应类型的主体是错误类型为hyper::error::Error 的流:

error[E0271]: type mismatch resolving `<ApiService as hyper::client::Service>::Error == hyper::Error`
  --> src/main.rs:14:10
   |
14 |         .bind(&address, move || Ok(ApiService {}))
   |          ^^^^ expected enum `Error`, found enum `hyper::Error`
   |
   = note: expected type `Error`
              found type `hyper::Error`

【问题讨论】:

    标签: rust hyper


    【解决方案1】:

    因为服务器的最终目标是向用户返回响应,所以我找到了一个可接受的解决方案,即创建一个 finalize 函数,将处理请求时遇到的错误转换为格式正确的响应,并将这些错误视为从 hyper 的角度来看没有错误。我需要充实这个想法(例如,将超错误作为错误传递),但我相信基本想法是合理的。

    以下代码修改问题中的代码以执行此操作:

    extern crate diesel;
    extern crate futures;
    extern crate hyper;
    #[macro_use]
    extern crate serde_derive;
    
    use futures::future::{ok, Future};
    use hyper::StatusCode;
    use hyper::server::{Request, Response, Service};
    
    fn main() {
        let address = "127.0.0.1:8080".parse().unwrap();
        let server = hyper::server::Http::new()
            .bind(&address, move || Ok(ApiService {}))
            .unwrap();
        server.run().unwrap();
    }
    
    fn finalize(result: Result<Response, Error>) -> FutureResult<Response, hyper::Error> {
        match result {
            Ok(response) => ok(response),
            Err(error) => {
                let response_body =
                    json!({"status": 500, "description": error.description()}).to_string();
                ok(Response::new()
                    .with_status(StatusCode::InternalServerError)
                    .with_header(ContentLength(response_body.len() as u64))
                    .with_body(response_body))
            }
        }
    }
    
    pub struct ApiService;
    
    impl Service for ApiService {
        type Request = Request;
        type Response = Response;
        type Error = hyper::Error;
        type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
    
        fn call(&self, request: Request) -> Self::Future {
            let response = Ok(Response::new().with_status(StatusCode::Ok));
            Box::new(finalize(response))
        }
    }
    
    #[derive(Debug)]
    pub enum Error {
        Request(hyper::Error),
        DatabaseResult(diesel::result::Error),
        DatabaseConnection(diesel::ConnectionError),
        Other(String),
    }
    
    // omitted impl of Display, std::error::Error for brevity
    

    【讨论】:

      【解决方案2】:

      您可以为您的 Error 类型实现 std::convert::From 特征。例如。对于hyper::Error 案例:

      impl From<hyper::Error> for Error {
          fn from(error: hyper::Error) -> Self {
              Error::Request(error)
          }
      }
      

      【讨论】:

      • 我不明白这是如何解决最初的问题的。这允许从 Hyper 的错误转换为用户的错误,但问题是相反的——代码需要返回 Hyper 的错误,而用户的错误正在被返回。你能edit你的答案来展示它在原始代码的上下文中是如何工作的吗?
      • 阅读提供的编译器错误,我得到了相反的结果:即代码需要返回用户的错误类型,但实际上返回的是Hyper的错误类型。
      猜你喜欢
      • 2021-10-19
      • 2019-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-14
      • 1970-01-01
      • 2017-05-25
      • 1970-01-01
      相关资源
      最近更新 更多