gpt4 book ai didi

http - 如何使用拒绝和问号运算符处理 Warp 中的错误?

转载 作者:行者123 更新时间:2023-12-03 07:38:01 25 4
gpt4 key购买 nike

使用 warp.rs 0.2.2 ,让我们考虑一个基本的 Web 服务,它有一个路由 GET / :

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let getRoot = warp::get().and(warp::path::end()).and_then(routes::getRoot);
warp::serve(getRoot).run(([0, 0, 0, 0], 3030)).await;
Ok(())
}
我的目标是使用 ?用于路由处理程序中的错误处理,所以让我们在 crate::routes 中编写一个可以出错并提前返回的处理程序:
use crate::errors::ServiceError;
use url::Url;

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 !")
}
这个版本有效。
这里是 Url::parse() 返回的错误是 url::ParseError要在错误类型之间进行转换,从 url::ParseErrorServiceError ,然后从 ServiceErrorwarp::Rejection , 我在 crate::errors 中写了一些错误助手:
#[derive(thiserror::Error, Debug)]
pub enum ServiceError {
#[error(transparent)]
Other(#[from] anyhow::Error), // source and Display delegate to anyhow::Error
}
impl warp::reject::Reject for ServiceError {}
impl From<ServiceError> for warp::reject::Rejection {
fn from(e: ServiceError) -> Self {
warp::reject::custom(e)
}
}
impl From<url::ParseError> for ServiceError {
fn from(e: url::ParseError) -> Self {
ServiceError::Other(e.into())
}
}

现在,上述工作,我正在尝试缩短第二个代码块以使用 ?直接用于错误处理,并自动从底层错误(此处为 url::ParseError )转换为 warp::Rejection .
这是我尝试过的:
use crate::errors::ServiceError;
use url::Url;

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

Ok("Hello world !")
}
url::ParseErrorUrl::Parse 返回将正常转换为 ServiceError 以返回,但从我的处理程序返回 ServiceError 不起作用。
我得到的第一个编译错误是:
error[E0277]: the trait bound `errors::ServiceError: warp::reject::sealed::CombineRejection<warp::reject::Rejection>` is not satisfied
--> src/main.rs:102:54
|
102 | let getRoot = warp::get().and(warp::path::end()).and_then(routes::getRoot);
| ^^^^^^^^ the trait `warp::reject::sealed::CombineRejection<warp::reject::Rejection>` is not implemented for `errors::ServiceError`
有没有办法可以使用 ? 来保持简短的错误处理?只有或者:
  • 制作 ServiceError实现warp::reject::sealed::CombineRejection<warp::reject::Rejection> ?
  • 解决这个问题?
  • 最佳答案

    你可以实现From将您的错误类型转换为 warp::Rejection 使用 reject::custom . Rejection封装自定义类型,您可以稍后选择在 recover 中进行检查处理程序。
    这个例子使用了一个简单的错误结构,但如果你有一个错误枚举,你可以匹配恢复处理程序中的变体,并根据需要执行不同的逻辑。

    use serde::Deserialize;
    use snafu::{ensure, Snafu};
    use std::convert::Infallible;
    use warp::{
    filters::{any, query, BoxedFilter},
    http::StatusCode,
    reject::Reject,
    Filter, Rejection, Reply,
    };

    // A normal error type, created by SNAFU
    #[derive(Debug, Snafu)]
    #[snafu(display("Expected a value less than 10, but it was {}", value))]
    struct LessThanTenError {
    value: i32,
    }

    // A function that might fail
    fn validate(value: i32) -> Result<i32, LessThanTenError> {
    ensure!(value < 10, LessThanTenContext { value });
    Ok(value)
    }

    // We need a custom type to later extract from the `Rejection`. In
    // this case, we can reuse the error type itself.
    impl Reject for LessThanTenError {}

    // To allow using `?`, we implement a conversion from our error to
    // `Rejection`
    impl From<LessThanTenError> for Rejection {
    fn from(other: LessThanTenError) -> Self {
    warp::reject::custom(other)
    }
    }

    #[tokio::main]
    async fn main() {
    let api = simple_math().recover(report_invalid);

    let p: std::net::SocketAddr = "0.0.0.0:8888".parse().unwrap();
    warp::serve(api).run(p).await;
    }

    #[derive(Debug, Deserialize)]
    struct QueryParams {
    a: i32,
    b: i32,
    }

    fn simple_math() -> BoxedFilter<(impl Reply,)> {
    any::any()
    .and(query::query())
    .and_then(|args: QueryParams| async move {
    // Look at us using those question marks!
    let a = validate(args.a)?;
    let b = validate(args.b)?;
    let sum = validate(a + b)?;

    // We specify that we are returning an error type of
    // `Rejection`, which allows the compiler to know what
    // type to convert to when using `?` here.
    Ok::<_, Rejection>(format!("The sum is {}", sum))
    })
    .boxed()
    }

    async fn report_invalid(r: Rejection) -> Result<impl Reply, Infallible> {
    if let Some(e) = r.find::<LessThanTenError>() {
    // It was our specific error type, do whatever we want. We
    // will just print out the error text.
    Ok(warp::reply::with_status(
    e.to_string(),
    StatusCode::BAD_REQUEST,
    ))
    } else {
    // Do prettier error reporting for the default error here.
    Ok(warp::reply::with_status(
    String::from("Something bad happened"),
    StatusCode::INTERNAL_SERVER_ERROR,
    ))
    }
    }
    [dependencies]
    serde = { version = "1.0.118", features = ["derive"] }
    snafu = "0.6.10"
    tokio = { version = "0.2.23", features = ["full"] }
    warp = "0.2.5"
    % curl 'http://127.0.0.1:8888'
    < HTTP/1.1 500 Internal Server Error
    Something bad happened

    % curl -v 'http://127.0.0.1:8888?a=1&b=2'
    < HTTP/1.1 200 OK
    The sum is 3

    % curl -v 'http://127.0.0.1:8888?a=6&b=5'
    < HTTP/1.1 400 Bad Request
    Expected a value less than 10, but it was 11
    也可以看看:
  • Is there a way to do validation as part of a filter in Warp?
  • When should I implement std::convert::From vs std::convert::Into?
  • How do you define custom `Error` types in Rust?
  • 关于http - 如何使用拒绝和问号运算符处理 Warp 中的错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61013311/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com