在Rust Axum中用结构体接收自定义请求头及TypedHeader示例
使用Axum的TypedHeader接收自定义请求头
TypedHeader完全支持自定义请求头,只需为每个自定义头实现Header trait即可。以下是两种实现方案,既可以单独接收每个自定义头,也可以封装成结构体统一接收。
方案1:单独接收每个自定义头(推荐用headers宏简化)
首先在Cargo.toml中添加依赖(如果还没加):
[dependencies] axum = "0.7" http = "1.0" headers = "0.4" serde = { version = "1.0", features = ["derive"] }
然后用headers宏快速定义自定义请求头,无需手动实现Header trait:
use headers::Header; use axum::extract::TypedHeader; // 定义Y-VERSION自定义头 headers::header! { (YVersion, "Y-VERSION") => [String] } // 定义Z-TYPE自定义头 headers::header! { (ZType, "Z-TYPE") => [String] } // 定义Z-SESSION自定义头 headers::header! { (ZSession, "Z-SESSION") => [String] }
接下来修改处理器签名,直接通过TypedHeader提取每个自定义头:
#[debug_handler] pub async fn find_balance( Path(balance_string): Path<String>, query_params: Query<QueryParams>, TypedHeader(y_version): TypedHeader<YVersion>, TypedHeader(z_type): TypedHeader<ZType>, TypedHeader(z_session): TypedHeader<ZSession>, JwtClaims(user): JwtClaims<RegisteredClaims>, State(client): State<Client> ) -> Result<Json<BalanceDTO>, Error> { // 使用自定义头的值 let version = y_version.0; let type_ = z_type.0; let session = z_session.0; // 后续业务逻辑... }
方案2:封装成结构体统一接收
如果你希望像Query那样用一个结构体接收所有自定义头,可以实现FromRequest trait:
use axum::{ extract::FromRequest, http::{Request, StatusCode, Error}, async_trait, }; // 注意:`type`是Rust关键字,改用`type_`或`r#type` #[derive(Debug, Clone)] pub struct CustomHeaders { pub version: String, pub type_: String, pub session: String, } #[async_trait] impl<S> FromRequest<S> for CustomHeaders where S: Send + Sync, { type Rejection = Error; async fn from_request(req: Request<axum::body::Body>, _state: &S) -> Result<Self, Self::Rejection> { let headers = req.headers(); // 提取并校验每个自定义头 let version = headers.get("Y-VERSION") .ok_or_else(|| Error::from_http_status_code(StatusCode::BAD_REQUEST))? .to_str() .map_err(|_| Error::from_http_status_code(StatusCode::BAD_REQUEST))? .to_string(); let type_ = headers.get("Z-TYPE") .ok_or_else(|| Error::from_http_status_code(StatusCode::BAD_REQUEST))? .to_str() .map_err(|_| Error::from_http_status_code(StatusCode::BAD_REQUEST))? .to_string(); let session = headers.get("Z-SESSION") .ok_or_else(|| Error::from_http_status_code(StatusCode::BAD_REQUEST))? .to_str() .map_err(|_| Error::from_http_status_code(StatusCode::BAD_REQUEST))? .to_string(); Ok(Self { version, type_, session }) } }
然后在处理器中直接使用这个结构体:
#[debug_handler] pub async fn find_balance( Path(balance_string): Path<String>, query_params: Query<QueryParams>, custom_headers: CustomHeaders, JwtClaims(user): JwtClaims<RegisteredClaims>, State(client): State<Client> ) -> Result<Json<BalanceDTO>, Error> { // 直接访问结构体字段 println!("Version: {}", custom_headers.version); println!("Type: {}", custom_headers.type_); println!("Session: {}", custom_headers.session); // 后续业务逻辑... }
内容的提问来源于stack exchange,提问作者swerts
相关产品推荐
相关产品推荐

