41 lines
2.0 KiB
Rust
41 lines
2.0 KiB
Rust
use axum::{body::Body, http::Request, middleware, Router};
|
||
use tower_http::trace::{DefaultOnFailure, DefaultOnRequest, DefaultOnResponse, TraceLayer};
|
||
use tracing::{info_span, Level};
|
||
|
||
use crate::{
|
||
error_middleware::normalize_error_response,
|
||
request_context::{attach_request_context, resolve_request_id},
|
||
response_headers::propagate_request_id_header,
|
||
state::AppState,
|
||
};
|
||
|
||
// 统一由这里构造 Axum 路由树,后续再逐项挂接中间件与业务路由。
|
||
pub fn build_router(state: AppState) -> Router {
|
||
Router::new()
|
||
// 错误归一化层放在 tracing 里侧,让 tracing 记录到最终对外返回的状态与错误体形态。
|
||
.layer(middleware::from_fn(normalize_error_response))
|
||
// 响应头回写放在错误归一化外侧,确保最终写回的是归一化后的最终响应。
|
||
.layer(middleware::from_fn(propagate_request_id_header))
|
||
// 当前阶段先统一挂接 HTTP tracing,后续 request_id、响应头与错误中间件继续在这里扩展。
|
||
.layer(
|
||
TraceLayer::new_for_http()
|
||
.make_span_with(|request: &Request<Body>| {
|
||
let request_id =
|
||
resolve_request_id(request).unwrap_or_else(|| "unknown".to_string());
|
||
|
||
info_span!(
|
||
"http.request",
|
||
method = %request.method(),
|
||
uri = %request.uri(),
|
||
request_id = %request_id,
|
||
)
|
||
})
|
||
.on_request(DefaultOnRequest::new().level(Level::INFO))
|
||
.on_response(DefaultOnResponse::new().level(Level::INFO))
|
||
.on_failure(DefaultOnFailure::new().level(Level::ERROR)),
|
||
)
|
||
// request_id 中间件先进入请求链,确保后续 tracing、错误处理和响应头层都能复用同一份请求标识。
|
||
.layer(middleware::from_fn(attach_request_context))
|
||
.with_state(state)
|
||
}
|