如果说 State 和 Json 只是用现成验货设备,那自定义 extractor 才是“自己造海关扫描仪”。
比如,我们定义一个“当前关员”提取器:
use axum::{
extract::FromRequestParts,
http::{
header::AUTHORIZATION,
request::Parts,
},
};
struct CurrentOfficer {
name: String,
}
impl<S> FromRequestParts<S> for CurrentOfficer
where
S: Send + Sync,
{
type Rejection = ApiError;
async fn from_request_parts(
parts: &mut Parts,
_state: &S,
) -> Result<Self, Self::Rejection> {
let value = parts
.headers
.get(AUTHORIZATION)
.and_then(|v| v.to_str().ok());
match value {
Some("Bearer gate-secret") => Ok(Self {
name: "north-gate-officer".to_owned(),
}),
_ => Err(ApiError::Unauthorized),
}
}
}然后 handler 就可以直接这么写:
async fn my_profile(officer: CurrentOfficer) -> String {
format!("当前执勤关员:{}", officer.name)
}这时候心智就非常美:
Handler 不再自己拆 Header
而是直接声明:
“我这个窗口只接收已经验明身份的关员”你会发现,Axum 的优雅感很大一部分就来自这里:
很多原本散落在 handler 里的脏活,可以被抽成类型化的提取器。
这会让你的窗口函数越来越像业务声明,而不是流水线噪音。