rust - 如何正确处理 Warp 路由的错误

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

主要.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,
        })
    }
}

最佳答案

你应该只使用 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可以在没有它的情况下通过简单地更改 .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;
}

https://stackoverflow.com/questions/68331445/

相关文章:

schema - Protocol Buffer 架构无效。导入 "google/protobuf/

c - 为什么 GTK 4 报告 "assertion ' GTK_IS_WIDGET(部件 )'

sass - Stylelint 禁用规则, "no-descending-specificity"

python - 多次拟合时 keras fit() 的历史

azure-devops - Azure Devops 管道 NPM 审计

sql - 如何获得日期 + 时间的确定性计算值

node.js - 修复创建新 Angular 项目时的上游依赖冲突

python - 我的损失函数在训练期间没有得到更小的值

javascript - A 帧动画框在特定区域随机移动

javascript - 如何减少 GridStack 网格元素的最小高度和重量?