首页 > 解决方案 > 有没有更简单的方法来创建自定义过滤器方法来调用 Warp 处理程序?

问题描述

而不是写这样的东西:

let hello = get()
    .and(path!(String))
    .and_then(|string| handlers::hello(string).map_err(warp::reject::custom))
    .boxed()

我希望能够写:

let hello = get()
    .and(path!(String))
    .handle(handlers::hello)

-> ->事情handle在哪里。and_thenmap_errboxed

现在我为每个 arity 处理程序使用一组特征。这是 2-arity 处理程序:

pub trait Handle2<A, B, Fut, R, F>
where
    R: Reject,
    F: Fn(A, B) -> Fut,
    Fut: Future<Output = Result<String, R>>,
{
    fn handle(self, f: F) -> BoxedFilter<(String,)>;
}

impl<A, B, Fut, R, F, T, Futr> Handle2<A, B, Fut, R, F> for T
where
    R: Reject,
    F: Fn(A, B) -> Fut + Clone + Sync + Send + 'static,
    Fut: Future<Output = Result<String, R>> + Send,
    Futr: Future<Output = Result<(A, B), Rejection>> + Send,
    T: Filter<Extract = (A, B), Error = Rejection, Future = Futr> + Sync + Send + 'static,
{
    fn handle(self, f: F) -> BoxedFilter<(String,)> {
        self.and_then(move |a, b| f(a, b).map_err(warp::reject::custom))
            .boxed()
    }
}

你可以在 Rust 中做到这一点真是太棒了,但有没有更简单的方法来实现这一点?

标签: rusttraitsrust-warp

解决方案


有。

在你的 main() 中声明了这样一条路线:

let routes = get().and(path("hello")).and_then(routes::getRoot);

您可以使用async语法糖将简单的处理程序自动转换为未来(0.3/std 处理程序)。这使得它实现了所有必要的特征,以将其用作warp::Filter

// routes/mod.rs

pub async fn getRoot() -> Result<impl warp::Reply, warp::Rejection> {
    Ok("Hello world !")
}

到目前为止很简单!现在你想要的仍然缺少的一件事是正确的错误处理warp::reject::custom

首先,让我们的处理程序返回一个错误:

// routes/mod.rs

pub async fn getRoot() -> Result<impl warp::Reply, warp::Rejection> {
    let _parsed_url = Url::parse(&"https://whydoesn.it/work?").map_err(ServiceError::from)?;
    Ok("Hello world !")
}

注意map_err(ServiceError::from)和返回类型warp::Rejection?我们需要将特定错误转换为自定义错误枚举(即 ServiceError,我们将很快定义它),然后提供一种将 ServiceError 自动转换为 warp::Rejection 的方法。

让我们通过创建一种方法来处理来自所有路由处理程序函数的错误来做到这一点:

// ./errors.rs

/// An internal error enum for representing all the possible failure states
#[derive(thiserror::Error, Debug)]
pub enum ServiceError {
    #[error("unacceptable !")]
    SomeSpecificWayOfFailing,
    #[error(transparent)]
    Other(#[from] Box<dyn std::error::Error + Sync + Send>), // catchAll error type
}
impl warp::reject::Reject for ServiceError {}
impl From<ServiceError> for warp::reject::Rejection {
    fn from(e: ServiceError) -> Self {
        warp::reject::custom(e)
    }
}

在我们的例子中,我给出的错误示例返回一个url::ParseError. 让我们添加一种将其映射到 ServiceError 的方法:

// ./errors.rs

impl From<url::ParseError> for ServiceError {
    fn from(e: url::ParseError) -> Self {
        ServiceError::Other(e.into()) // you can refine that and turn it into a more specific enum variant of ServiceError here
    }
}

你应该准备好了。现在添加一个新的路由/处理程序应该像添加一个异步函数一样简单(加上添加impl ServiceError::from你想要在处理程序函数中处理的任何新错误类型)


推荐阅读