如何使用axum(基于hyper)设置http超时



我来自果朗,在那里我可以简单地使用http.Server结构来进行超时选项,如:

func start() {
httpServer := &http.Server{
ReadTimeout:  "30s",
WriteTimeout: "1h",
//...
}
err = httpServer.ListenAndServe()
}

我现在使用axum{ version = "0.5.16", features = ["json"] },我想设置这些超时,但我找不到如何设置

你能帮我吗?

我知道axum正在使用hyper,你能帮我了解如何做到这一点吗?

我正在使用以下代码:

axum::Server::bind(&addr)
.serve(app.into_make_service())
.with_graceful_shutdown(shutdown_signal())
.await
.unwrap();

我建议您在tower_http中使用TimeoutLayer。您可以将其配置到您的axum服务器中,如下所示:

#[tokio::main]
async fn main() {
let service = ServiceBuilder::new()
.layer(HandleErrorLayer::new(handle_timeout_error))
.layer(TimeoutLayer::new(Duration::from_secs(30)));
let app = Router::new()
.route(
"/todos",
get(controller::list_todos).post(controller::create_todo),
)
.layer(service);
axum::Server::bind(&"127.0.0.1:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.expect("Failed to start server");
}

pub async fn handle_timeout_error(err: BoxError) -> AppError {
if err.is::<timeout::error::Elapsed>() {
AppError::RequestTimeout
} else {
AppError::Unexpected(err)
}
}

您需要自定义此代码,它只是一个示例,不会自行编译。

TimeoutLayertower_http的一部分,请参见此处:https://docs.rs/tower-http/latest/tower_http/index.html

您可能需要添加类似的内容

tower = { version = "0.4", features = ["timeout"] }

到您的Cargo.toml


如果你想知道AppError是什么以及为什么它可以从处理程序返回,那是因为我为它实现了IntoResponse(你并不严格需要它,你可以懒洋洋地返回类似(StatusCode::REQUEST_TIMEOUT, "Timeout")(,我只是把它包括在内,因为我认为它可能会有所帮助(:

#[derive(Debug)]
pub enum AppError {
NotFound,
ValidationFailed(ValidationErrors),
...
RequestTimeout,
...
}
impl Display for AppError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self {
AppError::ValidationFailed(_) => write!(f, "ValidationFailed"),
...
_ => Debug::fmt(self, f),
}
}
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let code = self.to_string();
let (status, err): (StatusCode, AppErrorJson) = match self {
...
AppError::NotFound => (
StatusCode::NOT_FOUND,
AppErrorJson::new(&code, "The requested resource could not be found", None),
),
AppError::ValidationFailed(e) => (
StatusCode::BAD_REQUEST,
AppErrorJson::new(
&code,
"Unable to validate request",
Some(AppErrorDetail::Validation(e)),
),
),
AppError::RequestTimeout => (
StatusCode::REQUEST_TIMEOUT,
AppErrorJson::new(&code, "Request timeout reached", None),
),
...
};
(status, Json(err)).into_response()
}
}
#[derive(Serialize)]
struct AppErrorJson<'a> {
code: &'a str,
message: Cow<'a, str>,
detail: Option<AppErrorDetail>,
}
impl<'a> AppErrorJson<'a> {
fn new<S>(code: &'a str, message: S, detail: Option<AppErrorDetail>) -> Self
where
S: Into<Cow<'a, str>>,
{
AppErrorJson {
code,
message: message.into(),
detail,
}
}
}

此外,如果您想知道为什么AppErrorJson.messageInto<Cow<'a, str>>,而不仅仅是String,请阅读以下内容:https://jwilm.io/blog/from-str-to-cow/作为一名Rust新手,它帮助我了解了如何有效地使用Rust不同的字符串类型。

相关内容

  • 没有找到相关文章

最新更新