背景: 正在给自己的小项目写 axum 全家桶的中间件.
代码片段:
/// Middleware for parsing and identifying Miku requests.
pub async fn miku_identification(request: AxumRequest, next: Next) -> Result<AxumResponse, ServerErrorExt> {
let (
Parts {
method,
uri,
version,
headers,
mut extensions,
..
},
body,
) = request.into_parts();
let queries = Queries::from_uri(&uri).unwrap_or_default();
// * Parse and identify APP type
if let Some(app_type) = AppTypeExt::get_from(&queries)? {
extensions.insert(app_type);
}
// * Parse and identify UserInfo
if let Some(user_info) = UserInfo::get_from(&queries)? {
extensions.insert(user_info);
}
let mut request = AxumRequest::new(body);
*request.method_mut() = method;
*request.uri_mut() = uri;
*request.version_mut() = version;
*request.headers_mut() = headers;
*request.extensions_mut() = extensions;
Ok(next.run(request).await)
}
相信各位都能看出来我在干嘛, 但是一眼看上去是相当别扭, 便问为什么不这么写:
pub async fn miku_identification(mut request: AxumRequest, next: Next) -> Result<AxumResponse, ServerErrorExt> {
let queries = Queries::from_uri(request.uri()).unwrap_or_default();
// * Parse and identify APP type
if let Some(app_type) = AppTypeExt::get_from(&queries)? {
request.extensions_mut().insert(app_type);
}
// * Parse and identify UserInfo
if let Some(user_info) = UserInfo::get_from(&queries)? {
request.extensions_mut().insert(user_info);
}
Ok(next.run(request).await)
}
会 Rust 的一眼就能看出来, Queries::from_uri 的时候拿了不可变引用, 下面不能可变引用了.
但是我寻思着我也没改动 uri 啊, 改的是 extension 啊, 烦闷, 把 request break down into parts 吧:
/// Middleware for parsing and identifying Miku requests.
pub async fn miku_identification(request: AxumRequest, next: Next) -> Result<AxumResponse, ServerErrorExt> {
let (
Parts {
method,
uri,
version,
headers,
mut extensions
},
body,
) = request.into_parts();
// ...
let mut request = AxumRequest::from_parts(Parts {
method,
uri,
version,
headers,
extensions
},
body
);
Ok(next.run(request).await)
}
各位肯定一眼看出有问题, 因为 Parts 下面还有个私有字段 _priv: ()
, 想半天没想明白干嘛的, 阻止下游私自构建 Parts? 自然也没提供方法从现有的 method 等组装... 恼火至极, 只能写出文首那种别扭的玩意.
求问各位观众还有没有什么更好的写法.
1 编:
再看了一遍文档, 发现给了个 builder, 最别扭的问题解决了...
1
openmynet 157 天前
```rust
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct TokenParams { pub token: String, } impl TokenParams { pub fn from_uri(uri: &axum::http::Uri) -> Result<Self, impl IntoResponse> { uri.query() .ok_or((StatusCode::BAD_REQUEST, "缺失参数")) .and_then(|q| { serde_qs::from_str::<TokenParams>(q) .map_err(|_| (StatusCode::FORBIDDEN, "缺失必要参数")) }) } } async fn authorize_demo(mut request: Request, next: Next) -> Result<Response, impl IntoResponse> { // 从 query 中获取 let valid = TokenParams::from_uri(request.uri()); match valid { Ok(valid) => { request.extensions_mut().insert(valid); Ok(next.run(request).await) } Err(err) => { return Err(err); } } } ``` |
2
fakeshadow 157 天前
```
let (app_type , user_info) = { let queries = Queries::from_uri(request.uri()).unwrap_or_default(); (AppTypeExt::get_from(&queries)?, UserInfo::get_from(&queries)?) }; if let Some(app_type) = app_type { request.extensions_mut().insert(app_type); } if let Some(user_info) = user_info { request.extensions_mut().insert(user_info); } ``` |