mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-26 00:00:23 +02:00
Revamp error handling model (#402)
* Revamp error handling model * changelog improvements and typo fixes * Fix a few more Infallible bounds * minor docs fixes
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
use axum::{
|
||||
body::Bytes,
|
||||
error_handling::HandleErrorLayer,
|
||||
extract::{ContentLengthLimit, Extension, Path},
|
||||
handler::{delete, get, Handler},
|
||||
http::StatusCode,
|
||||
@@ -18,7 +19,6 @@ use axum::{
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
convert::Infallible,
|
||||
net::SocketAddr,
|
||||
sync::{Arc, RwLock},
|
||||
time::Duration,
|
||||
@@ -52,16 +52,15 @@ async fn main() {
|
||||
// Add middleware to all routes
|
||||
.layer(
|
||||
ServiceBuilder::new()
|
||||
// Handle errors from middleware
|
||||
.layer(HandleErrorLayer::new(handle_error))
|
||||
.load_shed()
|
||||
.concurrency_limit(1024)
|
||||
.timeout(Duration::from_secs(10))
|
||||
.layer(TraceLayer::new_for_http())
|
||||
.layer(AddExtensionLayer::new(SharedState::default()))
|
||||
.into_inner(),
|
||||
)
|
||||
// Handle errors from middleware
|
||||
.handle_error(handle_error)
|
||||
.check_infallible();
|
||||
);
|
||||
|
||||
// Run our app with hyper
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
@@ -126,20 +125,20 @@ fn admin_routes() -> Router<BoxRoute> {
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn handle_error(error: BoxError) -> Result<impl IntoResponse, Infallible> {
|
||||
fn handle_error(error: BoxError) -> impl IntoResponse {
|
||||
if error.is::<tower::timeout::error::Elapsed>() {
|
||||
return Ok((StatusCode::REQUEST_TIMEOUT, Cow::from("request timed out")));
|
||||
return (StatusCode::REQUEST_TIMEOUT, Cow::from("request timed out"));
|
||||
}
|
||||
|
||||
if error.is::<tower::load_shed::error::Overloaded>() {
|
||||
return Ok((
|
||||
return (
|
||||
StatusCode::SERVICE_UNAVAILABLE,
|
||||
Cow::from("service is overloaded, try again later"),
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
Ok((
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Cow::from(format!("Unhandled internal error: {}", error)),
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
|
||||
use axum::{
|
||||
body::{Body, BoxBody, Bytes},
|
||||
error_handling::HandleErrorLayer,
|
||||
handler::post,
|
||||
http::{Request, Response},
|
||||
http::{Request, Response, StatusCode},
|
||||
Router,
|
||||
};
|
||||
use std::net::SocketAddr;
|
||||
use tower::{filter::AsyncFilterLayer, util::AndThenLayer, BoxError};
|
||||
use tower::{filter::AsyncFilterLayer, util::AndThenLayer, BoxError, ServiceBuilder};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
@@ -26,8 +27,17 @@ async fn main() {
|
||||
|
||||
let app = Router::new()
|
||||
.route("/", post(|| async move { "Hello from `POST /`" }))
|
||||
.layer(AsyncFilterLayer::new(map_request))
|
||||
.layer(AndThenLayer::new(map_response));
|
||||
.layer(
|
||||
ServiceBuilder::new()
|
||||
.layer(HandleErrorLayer::new(|error| {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Unhandled internal error: {}", error),
|
||||
)
|
||||
}))
|
||||
.layer(AndThenLayer::new(map_response))
|
||||
.layer(AsyncFilterLayer::new(map_request)),
|
||||
);
|
||||
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
tracing::debug!("listening on {}", addr);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
//! ```
|
||||
|
||||
use axum::{
|
||||
error_handling::HandleErrorExt,
|
||||
extract::TypedHeader,
|
||||
handler::get,
|
||||
http::StatusCode,
|
||||
@@ -28,10 +29,10 @@ async fn main() {
|
||||
ServeDir::new("examples/sse/assets").append_index_html_on_directories(true),
|
||||
)
|
||||
.handle_error(|error: std::io::Error| {
|
||||
Ok::<_, std::convert::Infallible>((
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Unhandled internal error: {}", error),
|
||||
))
|
||||
)
|
||||
});
|
||||
|
||||
// build our application with a route
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
//! cargo run -p example-static-file-server
|
||||
//! ```
|
||||
|
||||
use axum::{http::StatusCode, service, Router};
|
||||
use std::{convert::Infallible, net::SocketAddr};
|
||||
use axum::{error_handling::HandleErrorExt, http::StatusCode, service, Router};
|
||||
use std::net::SocketAddr;
|
||||
use tower_http::{services::ServeDir, trace::TraceLayer};
|
||||
|
||||
#[tokio::main]
|
||||
@@ -23,10 +23,10 @@ async fn main() {
|
||||
.nest(
|
||||
"/static",
|
||||
service::get(ServeDir::new(".")).handle_error(|error: std::io::Error| {
|
||||
Ok::<_, Infallible>((
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Unhandled internal error: {}", error),
|
||||
))
|
||||
)
|
||||
}),
|
||||
)
|
||||
.layer(TraceLayer::new_for_http());
|
||||
|
||||
+12
-16
@@ -14,6 +14,7 @@
|
||||
//! ```
|
||||
|
||||
use axum::{
|
||||
error_handling::HandleErrorLayer,
|
||||
extract::{Extension, Path, Query},
|
||||
handler::{get, patch},
|
||||
http::StatusCode,
|
||||
@@ -23,7 +24,6 @@ use axum::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
convert::Infallible,
|
||||
net::SocketAddr,
|
||||
sync::{Arc, RwLock},
|
||||
time::Duration,
|
||||
@@ -49,25 +49,21 @@ async fn main() {
|
||||
// Add middleware to all routes
|
||||
.layer(
|
||||
ServiceBuilder::new()
|
||||
.layer(HandleErrorLayer::new(|error: BoxError| {
|
||||
if error.is::<tower::timeout::error::Elapsed>() {
|
||||
Ok(StatusCode::REQUEST_TIMEOUT)
|
||||
} else {
|
||||
Err((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Unhandled internal error: {}", error),
|
||||
))
|
||||
}
|
||||
}))
|
||||
.timeout(Duration::from_secs(10))
|
||||
.layer(TraceLayer::new_for_http())
|
||||
.layer(AddExtensionLayer::new(db))
|
||||
.into_inner(),
|
||||
)
|
||||
.handle_error(|error: BoxError| {
|
||||
let result = if error.is::<tower::timeout::error::Elapsed>() {
|
||||
Ok(StatusCode::REQUEST_TIMEOUT)
|
||||
} else {
|
||||
Err((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Unhandled internal error: {}", error),
|
||||
))
|
||||
};
|
||||
|
||||
Ok::<_, Infallible>(result)
|
||||
})
|
||||
// Make sure all errors have been handled
|
||||
.check_infallible();
|
||||
);
|
||||
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
tracing::debug!("listening on {}", addr);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//! ```
|
||||
|
||||
use axum::{
|
||||
error_handling::HandleErrorExt,
|
||||
extract::{
|
||||
ws::{Message, WebSocket, WebSocketUpgrade},
|
||||
TypedHeader,
|
||||
@@ -38,10 +39,10 @@ async fn main() {
|
||||
ServeDir::new("examples/websockets/assets").append_index_html_on_directories(true),
|
||||
)
|
||||
.handle_error(|error: std::io::Error| {
|
||||
Ok::<_, std::convert::Infallible>((
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Unhandled internal error: {}", error),
|
||||
))
|
||||
)
|
||||
}),
|
||||
)
|
||||
// routes are matched from bottom to top, so we have to put `nest` at the
|
||||
|
||||
Reference in New Issue
Block a user