创建具有自定义错误类型的超级服务

Jas*_*ins 2 rust hyper

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

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

  2. 将非超级错误包装在hyper::error::Error. 这看起来很hacky。

  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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

Jas*_*ins 5

因为服务器的最终目标是向用户返回响应,所以我找到了一个可接受的解决方案是创建一个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
Run Code Online (Sandbox Code Playgroud)