【问题标题】:What is the most idiomatic way of handling errors in asynchronous handlers in actix-web?在 actix-web 中处理异步处理程序中的错误的最惯用的方法是什么?
【发布时间】:2019-07-08 06:13:40
【问题描述】:

我在 actix_web 中有一个异步处理程序,如果未设置多个标头,则该处理程序必须失败。我不明白在返回 Future 的函数中处理错误的最佳方法应该是什么。我基本上想要一个等同于 ? 的期货运算符。

这是我当前的代码:

r.post().with_async(
    move |req: HttpRequest, path: Path<EventPath>, body: Json<EventCreationRequest>| {
        let headers = req.headers();
        let client_id = match headers
            .get("x-client-id")
            .ok_or("Header not found")
            .and_then(|v| v.to_str().map_err(|_| "Invalid header content"))
        {
            Err(e) => return ok(HttpResponse::BadRequest().body(e)).responder(),
            Ok(v) => v.to_string(),
        };
        operation_that_returns_future()
            .map(|_| HttpResponse::Ok().body("OK!"))
            .responder()
    },
);

我已经通过匹配提前回报来解决期货缺少? 运算符的问题。但是,在我的代码中,我实际上需要确保存在一堆其他标头。

理想情况下,我想将匹配和早期返回逻辑提取到可重用的东西中,但在这种情况下,这迫使我创建一个宏。这似乎有点过头了,特别是如果语言中已经有一些东西可以让我做我想做的事。

处理这种情况最惯用的方法是什么?

【问题讨论】:

  • 很难回答您的问题,因为它不包含minimal reproducible example。我们无法分辨代码中存在哪些 crate(及其版本)、类型、特征、字段等。如果您尝试在Rust Playground 上重现您的错误,如果可能的话,这将使我们更容易为您提供帮助,否则在全新的 Cargo 项目中,然后在edit 您的问题中包含附加信息。您可以使用Rust-specific MCVE tips 来减少您在此处发布的原始代码。谢谢!

标签: rust future actix-web


【解决方案1】:

要处理错误,请返回失败的Future。例如,将标头检查为Future,然后将您的期货与.and_then 链接起来。一个技巧是保持期货的错误类型相同,以避免map_err。例如:

fn handler(req: HttpRequest) -> impl Future<Item = HttpResponse, Error = Error> {
    has_client_header(&req)
        .and_then(|client| operation_that_returns_future(client))
        .map(|result| HttpResponse::Ok().body(result))
}

fn has_client_header(req: &HttpRequest) -> impl Future<Item = String, Error = Error> {
    if let Some(Ok(client)) = req.headers().get("x-client-id").map(|h| h.to_str()) {
        future::ok(client.to_owned())
    } else {
        future::failed(ErrorBadRequest("invalid x-client-id header"))
    }
}

fn operation_that_returns_future(client: String) -> impl Future<Item = String, Error = Error> {
    future::ok(client)
}

结果:

$ curl localhost:8000
invalid x-client-id header⏎
$ curl localhost:8000 -H 'x-client-id: asdf'
asdf⏎

operation_that_returns_future 有其他错误类型时:

fn handler(req: HttpRequest) -> impl Future<Item = HttpResponse, Error = Error> {
    has_client_header(&req)
        .and_then(|client| {
            operation_that_returns_future(client)
                .map_err(|_| ErrorInternalServerError("operation failed"))
        })
        .map(|result| HttpResponse::Ok().body(result))
}

另一个技巧是使用failure crate,它提供failure::Error::from,将所有错误映射到一种类型,failure::Error

最后,您可能会发现 actix_web::guards 对于检查标头值很有用:

.guard(guard::Header("x-client-id", "special client"))

【讨论】:

    猜你喜欢
    • 2021-09-17
    • 1970-01-01
    • 2019-02-26
    • 2017-01-14
    • 2016-11-22
    • 1970-01-01
    • 2013-10-13
    • 2021-02-02
    • 1970-01-01
    相关资源
    最近更新 更多