如何在 rust-warp 中发送自定义错误消息?
How to send a custom error message in rust-warp?
我使用 warp(0.3.2) 来处理几条路线(POST /topup 和 POST /print):
// main.rs
let print_route = warp::path("print")
.and(warp::path::param::<String>())
.and(warp::post())
.and_then(handle_upload);
let topup_route = warp::path("topup")
.and(warp::post())
.and(warp::body::json())
.and_then(handle_topup);
let routes = root
.or(print_route)
.or(topup_route)
.recover(handle_rejection)
.with(warp::cors().allow_any_origin());
println!("Client is up and running at localhost:{}", PORT);
warp::serve(routes).run(([0, 0, 0, 0], PORT)).await;
在 handle_upload
和 handle_topup
函数上,我使用自定义错误类型 AppErr
use warp::{reject::Reject};
#[derive(Debug)]
pub struct AppErr {
pub reason: String,
}
impl Reject for AppErr {}
如果我需要在 handle_topup
或 handle_upload
的任何部分抛出错误,我只需像这样调用 warp::reject::custom()
函数:
let reason = format!("Error writing file to destination: {}", &path);
warp::reject::custom(AppErr { reason })
我给出的每个 reason
都应该转发给客户端,所以我只做了一个 handle_rejection
来将两个路由中的任何 AppErr
转换为将被发送的响应类型扭曲
// Custom rejection handler that maps rejections into responses.
async fn handle_rejection(err: Rejection) -> Result<impl Reply, std::convert::Infallible> {
if err.is_not_found() {
Ok(reply::with_status("NOT_FOUND", StatusCode::NOT_FOUND))
} else if let Some(e) = err.find::<AppErr>() {
Ok(reply::with_status(e.reason.as_str(), StatusCode::BAD_REQUEST))
} else {
eprintln!("unhandled rejection: {:?}", err);
Ok(reply::with_status(
"INTERNAL_SERVER_ERROR",
StatusCode::INTERNAL_SERVER_ERROR,
))
}
}
应该很简单,但是我对这行有问题
error[E0597]: `err` does not live long enough
--> src\main.rs:225:29
|
225 | } else if let Some(e) = err.find::<AppErr>() {
| ^^^^^^^^^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `err` is borrowed for `'static`
...
234 | }
| - `err` dropped here while still borrowed
如果它尝试克隆 e.reason
,它会抛出 temporary value dropped while borrowed
错误。
我的问题是为什么我不能使 e
中的任何内容可用于 if let Some(e) = err.find::<AppErr>()
的外部范围
err
不能在函数作用域之后借用(因为它被它消耗了)。因此,您需要拥有所需零件的所有权:
async fn handle_rejection(err: Rejection) -> Result<impl Reply, std::convert::Infallible> {
if err.is_not_found() {
Ok(reply::with_status("NOT_FOUND".to_string(), StatusCode::NOT_FOUND))
} else if let Some(e) = err.find::<AppErr>() {
Ok(reply::with_status(e.reason.as_str().to_string(), StatusCode::BAD_REQUEST))
} else {
eprintln!("unhandled rejection: {:?}", err);
Ok(reply::with_status(
"INTERNAL_SERVER_ERROR".to_string(),
StatusCode::INTERNAL_SERVER_ERROR,
))
}
}
String
实现了 Reply
(以及 &str
),您可以在 documentation
中找到更多信息
您的 if/else
分支将有不同的类型(&str
与 String
),在所有分支中使用 to_string
,或者您必须使用 Box<dyn Reply>
或使用 Cow
.
我使用 warp(0.3.2) 来处理几条路线(POST /topup 和 POST /print):
// main.rs
let print_route = warp::path("print")
.and(warp::path::param::<String>())
.and(warp::post())
.and_then(handle_upload);
let topup_route = warp::path("topup")
.and(warp::post())
.and(warp::body::json())
.and_then(handle_topup);
let routes = root
.or(print_route)
.or(topup_route)
.recover(handle_rejection)
.with(warp::cors().allow_any_origin());
println!("Client is up and running at localhost:{}", PORT);
warp::serve(routes).run(([0, 0, 0, 0], PORT)).await;
在 handle_upload
和 handle_topup
函数上,我使用自定义错误类型 AppErr
use warp::{reject::Reject};
#[derive(Debug)]
pub struct AppErr {
pub reason: String,
}
impl Reject for AppErr {}
如果我需要在 handle_topup
或 handle_upload
的任何部分抛出错误,我只需像这样调用 warp::reject::custom()
函数:
let reason = format!("Error writing file to destination: {}", &path);
warp::reject::custom(AppErr { reason })
我给出的每个 reason
都应该转发给客户端,所以我只做了一个 handle_rejection
来将两个路由中的任何 AppErr
转换为将被发送的响应类型扭曲
// Custom rejection handler that maps rejections into responses.
async fn handle_rejection(err: Rejection) -> Result<impl Reply, std::convert::Infallible> {
if err.is_not_found() {
Ok(reply::with_status("NOT_FOUND", StatusCode::NOT_FOUND))
} else if let Some(e) = err.find::<AppErr>() {
Ok(reply::with_status(e.reason.as_str(), StatusCode::BAD_REQUEST))
} else {
eprintln!("unhandled rejection: {:?}", err);
Ok(reply::with_status(
"INTERNAL_SERVER_ERROR",
StatusCode::INTERNAL_SERVER_ERROR,
))
}
}
应该很简单,但是我对这行有问题
error[E0597]: `err` does not live long enough
--> src\main.rs:225:29
|
225 | } else if let Some(e) = err.find::<AppErr>() {
| ^^^^^^^^^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `err` is borrowed for `'static`
...
234 | }
| - `err` dropped here while still borrowed
如果它尝试克隆 e.reason
,它会抛出 temporary value dropped while borrowed
错误。
我的问题是为什么我不能使 e
中的任何内容可用于 if let Some(e) = err.find::<AppErr>()
err
不能在函数作用域之后借用(因为它被它消耗了)。因此,您需要拥有所需零件的所有权:
async fn handle_rejection(err: Rejection) -> Result<impl Reply, std::convert::Infallible> {
if err.is_not_found() {
Ok(reply::with_status("NOT_FOUND".to_string(), StatusCode::NOT_FOUND))
} else if let Some(e) = err.find::<AppErr>() {
Ok(reply::with_status(e.reason.as_str().to_string(), StatusCode::BAD_REQUEST))
} else {
eprintln!("unhandled rejection: {:?}", err);
Ok(reply::with_status(
"INTERNAL_SERVER_ERROR".to_string(),
StatusCode::INTERNAL_SERVER_ERROR,
))
}
}
String
实现了 Reply
(以及 &str
),您可以在 documentation
您的 if/else
分支将有不同的类型(&str
与 String
),在所有分支中使用 to_string
,或者您必须使用 Box<dyn Reply>
或使用 Cow
.