Proper way to render custom error pages #2075
-
Hello! I want to change the default Axum error "pages" (just empty bodies) into custom templates. I have this code, which works, but I feel like it's an absolutely major hack. Is there a better way? use askama::Template;
use axum::{
http::{header::CONTENT_LENGTH, StatusCode},
middleware::map_response,
response::{IntoResponse, Response},
Router,
};
use itertools::Itertools;
#[derive(Template)]
#[template(source = "{{ error_code }}: {{ reason }}", ext = "txt")]
pub struct ErrorTemplate<'a> {
pub error_code: &'a str,
pub reason: &'a str,
}
async fn transform_error(response: Response) -> impl IntoResponse {
let (parts, body) = response.into_parts();
let status_num = parts.status.as_u16();
if status_num < 400 {
// We only care about client or server errors
return Response::from_parts(parts, body);
}
// Sniff the content-length and see if we have any data
if let Some(content_length) = parts.headers.get(CONTENT_LENGTH) {
if let Ok(len) = std::str::from_utf8(content_length.as_bytes())
.unwrap_or("0")
.parse::<usize>()
{
if len > 0 {
return Response::from_parts(parts, body);
}
}
}
let (error_code, reason) = parts
.status
.to_string()
.splitn(2, ' ')
.collect_tuple()
.map_or(
(format!("{:03}", status_num), parts.status.to_string()),
|(x, y)| (x.to_owned(), y.to_owned()),
);
let t = ErrorTemplate {
error_code: &error_code,
reason: &reason,
};
(parts.status, t).into_response()
}
#[tokio::main]
fn main() {
let router = Router::new()
.layer(map_response(transform_error))
// ...
// ...
} |
Beta Was this translation helpful? Give feedback.
Answered by
davidpdrsn
Jul 6, 2023
Replies: 1 comment 1 reply
-
That looks fine to me. |
Beta Was this translation helpful? Give feedback.
1 reply
Answer selected by
Elizafox
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
That looks fine to me.