2

我正在尝试将一个重要的经纱REST 应用程序构建到模块中,同时优雅地处理错误和拒绝。它没有按我预期的方式工作。考虑这个简单的应用程序:

main.rs

use warp_sample::routes;

#[tokio::main]
async fn main() {
    warp::serve(routes::convert_route()).run(([127, 0, 0, 1], 8080)).await;
}

路线.rs

use warp::{Filter, Rejection, Reply};
use crate::handlers;

pub fn convert_route() -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
    warp::path("convert")
        .and(warp::path::param::<String>())
        .map(|v: String| {
            handlers::convert_str(&v).or_else(|e| e)
        })
}

处理程序.rs

use warp::{Reply, Rejection};

pub fn convert_str(s: &str) -> Result<impl Reply, Rejection>{
    match s.parse::<i32>() {
        Ok(s) => Ok(warp::reply()),
        Err(_) => Err(warp::reject())
    }
}

这不会编译,因为在 routes.rs 我试图在闭包中返回一个 Rejection 结构,它与返回类型不匹配impl Reply

我怎样才能让它工作?我试图更改的返回类型,convert_route但这不适用于warp::serve.

对于奖励分数,您能否告诉我如何在成功时在处理程序中包含纯文本响应,以及在出现错误时如何包含不同的状态代码?

这对奖金不起作用,但它向您展示了我的想法。

pub fn convert_str(s: &str) -> Result<impl Reply, Rejection>{
    match s.parse::<i32>() {
        Ok(s) => Ok(warp::body(s)),
        Err(_) => Err(warp::Rejection {
            reason: Reason::BadRequest,
        })
    }
}
4

1 回答 1

0

你应该只map在你正在做的操作是无误的时候使用。如果您希望能够返回拒绝,则应and_then改为使用。在您的示例中,convert_route更改为下面的代码时可以正确编译。

pub fn convert_route() -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
    warp::path("convert")
        .and(warp::path::param::<String>())
        .and_then(|v: String| async move { convert_str(&v) })
}

当然,在这个例子中,convert_str它有点微不足道,convert_route可以通过简单地更改 in 的类型来重写.and(warp::path::param::<String>()),但我假设该函数更多地涉及到您的实际代码中。

作为奖励,您将需要创建自己的拒绝类型,这将允许您使用recover. 完整代码:

use warp::{hyper::StatusCode, reject::Reject, Filter, Rejection, Reply};

pub fn convert_route() -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
    warp::path("convert")
        .and(warp::path::param::<String>())
        .and_then(|v: String| async move { convert_str(&v) })
        .recover(|err: Rejection| async move {
            if let Some(ConversionError) = err.find() {
                Ok(StatusCode::BAD_REQUEST)
            } else {
                Err(err)
            }
        })
}

#[derive(Debug)]
struct ConversionError;
impl Reject for ConversionError {}

pub fn convert_str(s: &str) -> Result<impl Reply, Rejection> {
    match s.parse::<i32>() {
        Ok(s) => Ok(s.to_string()),
        Err(_) => Err(warp::reject::custom(ConversionError)),
    }
}

#[tokio::main]
async fn main() {
    warp::serve(convert_route())
        .run(([127, 0, 0, 1], 8080))
        .await;
}
于 2021-07-13T11:41:38.160 回答