51 lines
1.5 KiB
Rust
51 lines
1.5 KiB
Rust
use axum::{extract::Request, http::header::CONTENT_TYPE, middleware::Next, response::Response};
|
|
use tracing::{error, warn};
|
|
|
|
use crate::{
|
|
http_error::AppError,
|
|
request_context::{RequestContext, resolve_request_id},
|
|
};
|
|
|
|
pub async fn normalize_error_response(request: Request, next: Next) -> Response {
|
|
let request_id = resolve_request_id(&request);
|
|
let request_context = request.extensions().get::<RequestContext>().cloned();
|
|
let response = next.run(request).await;
|
|
|
|
if !should_normalize_error_response(&response) {
|
|
return response;
|
|
}
|
|
|
|
let app_error = AppError::from_status(response.status());
|
|
let status = response.status();
|
|
let request_id = request_id.as_deref().unwrap_or("unknown");
|
|
|
|
if status.is_server_error() {
|
|
error!(
|
|
%request_id,
|
|
status = status.as_u16(),
|
|
error_code = app_error.code(),
|
|
"request failed"
|
|
);
|
|
} else {
|
|
warn!(
|
|
%request_id,
|
|
status = status.as_u16(),
|
|
error_code = app_error.code(),
|
|
"request failed"
|
|
);
|
|
}
|
|
|
|
app_error.into_response_with_context(request_context.as_ref())
|
|
}
|
|
|
|
fn should_normalize_error_response(response: &Response) -> bool {
|
|
let status = response.status();
|
|
|
|
if !(status.is_client_error() || status.is_server_error()) {
|
|
return false;
|
|
}
|
|
|
|
// 当前阶段只兜底框架默认的空错误响应或非 JSON 错误响应,避免覆盖后续业务 handler 主动构造的错误 body。
|
|
!response.headers().contains_key(CONTENT_TYPE)
|
|
}
|