Rust查询字符串处理库serde-querystring的使用:高效序列化与反序列化URL查询参数
Rust查询字符串处理库serde-querystring的使用:高效序列化与反序列化URL查询参数
安装
# Cargo.toml
[dependencies]
serde-querystring = "0.3.0"
用法
您可以直接使用此crate中提供的解析器,每个解析器的测试中都有示例。
use serde_querystring::DuplicateQS;
let parsed = DuplicateQS::parse(b"foo=bar&foo=baz");
let values = parsed.values(b"foo"); // 将为您提供b"bar"和b"baz"的向量
或者您可以使用serde(使用serde
功能,默认启用)
use serde::Deserialize;
use serde_querystring::{from_str, ParseMode, DuplicateQS};
#[derive(Deserialize)]
struct MyStruct{
foo: Vec<String> // 或(String, u32)元组
}
let parsed: MyStruct = from_str("foo=bar&foo=2022", ParseMode::Duplicate).unwrap();
// 或
let parsed: MyStruct = DuplicateQS::parse(b"foo=bar&foo=baz").deserialize().unwrap();
还有用于actix_web
(serde-querystring-actix
)和axum
(serde-querystring-axum
)的crate,它们为其框架提供提取器,可以在不直接依赖核心crate的情况下使用。
解析器
简单模式
简单地解析键=值对,每个键只接受一个值。如果键重复,我们只收集最后一个值。
use serde_querystring::{UrlEncodedQS, ParseMode, from_str};
UrlEncodedQS::parse(b"key=value");
// 或
let res: MyStruct = from_str("foo=bar&key=value", ParseMode::UrlEncoded).unwrap();
重复键模式
通过重复键支持向量或值。
use serde_querystring::{DuplicateQS, ParseMode, from_str};
DuplicateQS::parse(b"foo=bar&foo=bar2&foo=bar3");
// 或
let res: MyStruct = from_str("foo=bar&foo=bar2&foo=bar3", ParseMode::Duplicate).unwrap();
分隔符模式
通过使用分隔符字节(例如b’|’)支持向量或值。
use serde_querystring::{DelimiterQS, ParseMode, from_str};
DelimiterQS::parse(b"foo=bar|bar2|bar3", b'|');
// 或
let res: MyStruct = from_str("foo=bar|bar2|bar3", ParseMode::Delimiter(b'|')).unwrap();
括号模式
通过使用括号和子键支持向量或值。
use serde_querystring::{BracketsQS, ParseMode, from_str};
BracketsQS::parse(b"foo[1]=bar&foo[2]=bar&foo[3]=bar");
// 或
let res: MyStruct = from_str("foo[1]=bar&foo[2]=bar&foo[3]=bar", ParseMode::Brackets).unwrap();
完整示例代码
use serde::{Deserialize, Serialize};
use serde_querystring::{from_str, to_string, ParseMode};
// 定义数据结构
#[derive(Debug, Serialize, Deserialize)]
struct QueryParams {
name: String,
age: u32,
tags: Vec<String>,
filters: Option<Vec<String>>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 示例查询字符串
let query_string = "name=John&age=30&tags=rust&tags=web&tags=serde";
// 反序列化:从查询字符串到结构体
let params: QueryParams = from_str(query_string, ParseMode::Duplicate)?;
println!("反序列化结果: {:?}", params);
// 序列化:从结构体到查询字符串
let new_params = QueryParams {
name: "Alice".to_string(),
age: 25,
tags: vec!["programming".to_string(), "backend".to_string()],
filters: Some(vec!["active".to_string(), "verified".to_string()]),
};
let serialized = to_string(&new_params, ParseMode::Duplicate)?;
println!("序列化结果: {}", serialized);
Ok(())
}
// 测试不同解析模式的示例
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple_mode() {
#[derive(Debug, Deserialize)]
struct SimpleParams {
key: String,
foo: String,
}
let query = "foo=bar&key=value";
let params: SimpleParams = from_str(query, ParseMode::UrlEncoded).unwrap();
assert_eq!(params.foo, "bar");
assert_eq!(params.key, "value");
}
#[test]
fn test_delimiter_mode() {
#[derive(Debug, Deserialize)]
struct DelimiterParams {
foo: Vec<String>,
}
let query = "foo=bar|baz|qux";
let params: DelimiterParams = from_str(query, ParseMode::Delimiter(b'|')).unwrap();
assert_eq!(params.foo, vec!["bar", "baz", "qux"]);
}
}
完整示例demo
use serde::{Deserialize, Serialize};
use serde_querystring::{from_str, to_string, ParseMode};
// 定义用户查询参数结构体
#[derive(Debug, Serialize, Deserialize)]
struct UserQuery {
id: u32, // 用户ID
username: String, // 用户名
roles: Vec<String>, // 用户角色列表
is_active: bool, // 是否活跃
page: Option<u32>, // 页码(可选)
per_page: Option<u32>, // 每页数量(可选)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== serde-querystring 完整使用示例 ===");
// 示例1:重复键模式解析
println!("\n1. 重复键模式解析:");
let query1 = "id=123&username=john_doe&roles=admin&roles=user&is_active=true&page=1&per_page=20";
let user1: UserQuery = from_str(query1, ParseMode::Duplicate)?;
println!("解析结果: {:?}", user1);
// 示例2:分隔符模式解析
println!("\n2. 分隔符模式解析:");
let query2 = "id=456&username=jane_smith&roles=moderator|user|guest&is_active=false";
let user2: UserQuery = from_str(query2, ParseMode::Delimiter(b'|'))?;
println!("解析结果: {:?}", user2);
// 示例3:简单模式解析(最后一个值生效)
println!("\n3. 简单模式解析:");
let query3 = "id=789&username=test_user&roles=admin&roles=user";
let user3: UserQuery = from_str(query3, ParseMode::UrlEncoded)?;
println!("解析结果: {:?}", user3);
// 示例4:序列化为查询字符串
println!("\n4. 序列化为查询字符串:");
let new_user = UserQuery {
id: 999,
username: "new_user".to_string(),
roles: vec!["admin".to_string(), "editor".to_string()],
is_active: true,
page: Some(2),
per_page: Some(50),
};
let serialized = to_string(&new_user, ParseMode::Duplicate)?;
println!("序列化结果: {}", serialized);
// 示例5:处理可选字段
println!("\n5. 处理可选字段:");
let query5 = "id=111&username=optional_user&is_active=true";
let user5: UserQuery = from_str(query5, ParseMode::Duplicate)?;
println!("解析结果: {:?}", user5);
println!("页码: {:?}, 每页数量: {:?}", user5.page, user5.per_page);
Ok(())
}
// 错误处理示例
fn handle_query_errors() {
println!("\n=== 错误处理示例 ===");
// 无效查询字符串
let invalid_query = "invalid_format";
match from_str::<UserQuery>(invalid_query, ParseMode::Duplicate) {
Ok(user) => println!("成功解析: {:?}", user),
Err(e) => println!("解析错误: {}", e),
}
// 类型不匹配
let type_mismatch = "id=not_number&username=test";
match from_str::<UserQuery>(type_mismatch, ParseMode::Duplicate) {
Ok(user) => println!("成功解析: {:?}", user),
Err(e) => println!("类型错误: {}", e),
}
}
// 运行示例
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_all_parse_modes() {
// 测试所有解析模式
let query = "roles=admin|user|guest";
// 分隔符模式
let user1: UserQuery = from_str("id=1&username=test&is_active=true", ParseMode::Delimiter(b'|')).unwrap();
assert_eq!(user1.id, 1);
// 重复键模式
let user2: UserQuery = from_str("id=2&username=test2&roles=admin&roles=user", ParseMode::Duplicate).unwrap();
assert_eq!(user2.roles.len(), 2);
// 简单模式
let user3: UserQuery = from_str("id=3&username=test3&roles=admin&roles=user", ParseMode::UrlEncoded).unwrap();
assert_eq!(user3.roles.len(), 1); // 只保留最后一个值
}
#[test]
fn test_serialization() {
let user = UserQuery {
id: 100,
username: "serialize_test".to_string(),
roles: vec!["role1".to_string(), "role2".to_string()],
is_active: true,
page: None,
per_page: None,
};
let serialized = to_string(&user, ParseMode::Duplicate).unwrap();
assert!(serialized.contains("id=100"));
assert!(serialized.contains("username=serialize_test"));
}
}
许可证
此项目根据以下任一许可证授权:
- Apache License, Version 2.0
- MIT license
由您选择。
1 回复
serde-querystring:高效的Rust查询字符串处理库
概述
serde-querystring是一个专门用于处理URL查询字符串的Rust库,它基于serde框架提供了高效的序列化和反序列化功能。该库特别适合处理Web应用中的URL参数,支持各种复杂的数据结构。
主要特性
- 支持基本数据类型(字符串、数字、布尔值)
- 处理数组和嵌套结构
- 自定义键名映射
- 错误处理和验证
- 零拷贝解析
安装方法
在Cargo.toml中添加依赖:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde-querystring = "0.2"
基本用法示例
1. 反序列化查询字符串
use serde::Deserialize;
use serde_querystring::from_str;
// 定义用户查询结构体
#[derive(Debug, Deserialize)]
struct UserQuery {
name: String,
age: u32,
active: bool,
}
fn main() {
let query = "name=John&age=25&active=true";
let user: UserQuery = from_str(query).unwrap();
println!("{:?}", user);
// 输出: UserQuery { name: "John", age: 25, active: true }
}
2. 处理数组参数
// 定义搜索参数结构体
#[derive(Debug, Deserialize)]
struct SearchParams {
q: String,
tags: Vec<String>,
page: u32,
}
fn main() {
let query = "q=rust&tags=programming&tags=web&page=1";
let params: SearchParams = from_str(query).unwrap();
println!("搜索: {}", params.q);
println!("标签: {:?}", params.tags);
// 输出: 搜索: rust
// 输出: 标签: ["programming", "web"]
}
3. 嵌套结构处理
// 定义过滤器结构体
#[derive(Debug, Deserialize)]
struct Filters {
category: String,
price_range: PriceRange,
}
// 定义价格范围结构体
#[derive(Debug, Deserialize)]
struct PriceRange {
min: f32,
max: f32,
}
fn main() {
let query = "category=electronics&price_range[min]=100&price_range[max]=500";
let filters: Filters = from_str(query).unwrap();
println!("价格范围: {}-{}", filters.price_range.min, filters.price_range.max);
}
4. 序列化为查询字符串
use serde::Serialize;
use serde_querystring::to_string;
// 定义分页结构体
#[derive(Debug, Serialize)]
struct Pagination {
page: u32,
limit: u32,
sort: String,
}
fn main() {
let pagination = Pagination {
page: 2,
limit: 20,
sort: "date".to_string(),
};
let query_string = to_string(&pagination).unwrap();
println!("{}", query_string);
// 输出: page=2&limit=20&sort=date
}
高级功能
自定义字段映射
use serde::Deserialize;
// 定义用户结构体,使用自定义字段映射
#[derive(Debug, Deserialize)]
struct User {
#[serde(rename = "user_name")]
name: String,
#[serde(rename = "user_age")]
age: u32,
}
fn main() {
let query = "user_name=Alice&user_age=30";
let user: User = from_str(query).unwrap();
}
可选字段处理
// 定义查询参数结构体,包含可选字段
#[derive(Debug, Deserialize)]
struct QueryParams {
required: String,
optional: Option<String>,
}
fn main() {
let query = "required=value";
let params: QueryParams = from_str(query).unwrap();
println!("可选字段: {:?}", params.optional);
// 输出: 可选字段: None
}
错误处理
// 错误处理函数示例
fn parse_query(query: &str) -> Result<UserQuery, serde_querystring::Error> {
let result: Result<UserQuery, _> = from_str(query);
match result {
Ok(user) => Ok(user),
Err(e) => {
eprintln!("解析错误: {}", e);
Err(e)
}
}
}
最佳实践
- 始终处理可能的解析错误
- 为可选字段使用Option类型
- 使用适当的错误类型进行验证
- 考虑查询字符串的长度限制
这个库为Rust开发者提供了强大而灵活的查询字符串处理能力,特别适合Web应用和API开发场景。
完整示例代码
use serde::{Deserialize, Serialize};
use serde_querystring::{from_str, to_string};
// 用户信息结构体
#[derive(Debug, Serialize, Deserialize)]
struct User {
#[serde(rename = "user_id")]
id: u32,
#[serde(rename = "user_name")]
name: String,
#[serde(rename = "user_email")]
email: Option<String>,
roles: Vec<String>,
is_active: bool,
}
// 分页参数结构体
#[derive(Debug, Serialize, Deserialize)]
struct Pagination {
page: u32,
per_page: u32,
sort_by: Option<String>,
order: Option<String>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 示例1: 反序列化复杂查询字符串
let user_query = "user_id=123&user_name=John+Doe&roles=admin&roles=user&is_active=true";
let user: User = from_str(user_query)?;
println!("用户信息: {:?}", user);
// 示例2: 序列化为查询字符串
let pagination = Pagination {
page: 1,
per_page: 20,
sort_by: Some("name".to_string()),
order: Some("desc".to_string()),
};
let query_string = to_string(&pagination)?;
println!("查询字符串: {}", query_string);
// 示例3: 处理错误情况
let invalid_query = "user_id=abc&user_name=John"; // user_id应该是数字
match from_str::<User>(invalid_query) {
Ok(user) => println!("成功解析: {:?}", user),
Err(e) => println!("解析错误: {}", e),
}
Ok(())
}
// 错误处理包装函数
fn safe_parse<T: for<'de> Deserialize<'de>>(query: &str) -> Result<T, String> {
from_str(query).map_err(|e| format!("解析失败: {}", e))
}
// 单元测试示例
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_parsing() {
let query = "user_id=456&user_name=Test&is_active=false";
let user: User = from_str(query).unwrap();
assert_eq!(user.id, 456);
assert_eq!(user.name, "Test");
assert_eq!(user.is_active, false);
}
#[test]
fn test_array_parsing() {
let query = "user_id=789&user_name=ArrayTest&roles=admin&roles=moderator&roles=user";
let user: User = from_str(query).unwrap();
assert_eq!(user.roles.len(), 3);
assert!(user.roles.contains(&"admin".to_string()));
}
}