Rust JSON标准化库serde_json_canonicalizer的使用,实现JSON数据的规范化解析与序列化
Rust JSON标准化库serde_json_canonicalizer的使用,实现JSON数据的规范化解析与序列化
简介
serde_json_canonicalizer是一个与RFC 8785兼容的JSON规范化方案输出库,用于serde_json。
JSON规范化方案RFC-8785定义了一种JSON序列化方案,允许在依赖数据字节级重现的加密操作中使用JSON数据。它可以代替将序列化格式存储为BASE64编码字符串或类似的打包方式,使得在处理可以规范化后再输入加密函数的JSON格式数据时更加容易。
使用示例
use serde_json_canonicalizer::{to_string, to_vec};
#[derive(serde::Serialize)]
struct Data {
c: isize,
b: bool,
a: String,
}
let data = Data { c: 120, b: false, a: "Hello!".to_string() };
let expected = r#"{"a":"Hello!","b":false,"c":120}"#;
// 序列化为字符串或字节,可替代serde_json
let json_string = to_string(&data).unwrap();
let json_bytes = to_vec(&data).unwrap();
assert_eq!(json_string, expected);
assert_eq!(json_bytes, expected.as_bytes());
完整示例代码
// 添加依赖到Cargo.toml
// serde_json_canonicalizer = "0.3.0"
// serde = { version = "1.0", features = ["derive"] }
use serde::{Serialize, Deserialize};
use serde_json_canonicalizer::{to_string, to_vec, from_str};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct User {
id: u32,
username: String,
email: String,
is_active: bool,
}
fn main() {
// 创建示例数据
let user = User {
id: 42,
username: "john_doe".to_string(),
email: "john@example.com".to_string(),
is_active: true,
};
// 序列化为规范化JSON字符串
let canonical_json = to_string(&user).unwrap();
println!("Canonical JSON: {}", canonical_json);
// 序列化为规范化JSON字节
let canonical_bytes = to_vec(&user).unwrap();
println!("Canonical Bytes: {:?}", canonical_bytes);
// 反序列化
let deserialized: User = from_str(&canonical_json).unwrap();
println!("Deserialized: {:?}", deserialized);
// 验证数据一致性
assert_eq!(user, deserialized);
// 验证规范化输出
// 即使字段顺序不同,规范化输出也会保持一致
let expected_json = r#"{"email":"john@example.com","id":42,"is_active":true,"username":"john_doe"}"#;
assert_eq!(canonical_json, expected_json);
}
许可证
MIT许可证
与serde_jcs的比较
创建这个库是因为serde_jcs似乎已被放弃,且该仓库中的问题列出了一些与RFC不同的地方。这个库旨在100%兼容RFC,成为多语言环境中的合适实现。
1 回复
Rust JSON标准化库serde_json_canonicalizer使用指南
概述
serde_json_canonicalizer
是一个Rust库,用于实现JSON数据的规范化(canonical)解析与序列化。它基于流行的serde_json
库,添加了对JSON数据的规范化处理能力,确保相同的逻辑内容总是产生相同的字节序列输出。
主要特性
- 将JSON数据转换为规范化的形式
- 确保相同的JSON数据总是产生相同的字符串表示
- 处理浮点数的规范化表示
- 保持键的排序一致性
- 无空格和换行的紧凑输出
安装
在Cargo.toml中添加依赖:
[dependencies]
serde_json_canonicalizer = "0.1"
serde = { version = "1.0", features = ["derive"] }
基本使用方法
规范化序列化
use serde_json_canonicalizer::to_vec;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Person {
name: String,
age: u32,
hobbies: Vec<String>,
}
fn main() {
let person = Person {
name: "Alice".to_string(),
age: 30,
hobbies: vec!["reading".to_string(), "hiking".to_string()],
};
// 规范化序列化
let canonical_json = to_vec(&person).unwrap();
println!("{}", String::from_utf8_lossy(&canonical_json));
// 输出: {"age":30,"hobbies":["reading","hiking"],"name":"Alice"}
}
规范化解析
use serde_json_canonicalizer::from_slice;
fn main() {
let json_data = br#"{
"name": "Bob",
"age": 25,
"active": true
}"#;
// 规范化解析
let parsed: serde_json::Value = from_slice(json_data).unwrap();
println!("{:?}", parsed);
// 输出: Object({"active": Bool(true), "age": Number(25), "name": String("Bob")})
}
高级用法
自定义类型规范化
use serde_json_canonicalizer::{to_vec, from_slice};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Product {
id: u64,
name: String,
price: f64,
categories: Vec<String>,
}
fn main() {
let product = Product {
id: 12345,
name: "Rust Programming Book".to_string(),
price: 39.99,
categories: vec!["Programming".to_string(), "Books".to_string()],
};
// 序列化为规范化JSON
let json_data = to_vec(&product).unwrap();
// 从规范化JSON解析回来
let parsed_product: Product = from_slice(&json_data).unwrap();
assert_eq!(product, parsed_product);
}
处理浮点数规范化
use serde_json_canonicalizer::to_string;
fn main() {
let data = serde_json::json!({
"float1": 3.141592653589793,
"float2": 1.0,
"float3": 2.0e10,
"float4": -0.0
});
let canonical = to_string(&data).unwrap();
println!("{}", canonical);
// 输出: {"float1":3.141592653589793,"float2":1.0,"float3":2.0e10,"float4":-0.0}
}
完整示例
以下是一个完整的示例,展示如何使用serde_json_canonicalizer
进行JSON数据的规范化处理和验证:
use serde::{Serialize, Deserialize};
use serde_json_canonicalizer::{to_vec, from_slice};
// 定义一个用户结构体
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct User {
id: u64,
username: String,
email: String,
permissions: Vec<String>,
is_active: bool,
}
fn main() {
// 创建用户实例
let user = User {
id: 123456,
username: "rustacean".to_string(),
email: "rust@example.com".to_string(),
permissions: vec!["read".to_string(), "write".to_string()],
is_active: true,
};
// 1. 序列化为规范化JSON
let canonical_json = to_vec(&user).unwrap();
println!("规范化JSON输出:");
println!("{}", String::from_utf8_lossy(&canonical_json));
// 输出: {"email":"rust@example.com","id":123456,"is_active":true,"permissions":["read","write"],"username":"rustacean"}
// 2. 重新解析规范化JSON
let parsed_user: User = from_slice(&canonical_json).unwrap();
println!("\n解析后的用户数据:");
println!("{:?}", parsed_user);
// 3. 验证数据一致性
assert_eq!(user, parsed_user);
println!("\n验证通过 - 原始数据与解析后数据完全一致");
// 4. 处理不同格式的相同数据
let messy_json = br#"{
"username": "rustacean",
"email": "rust@example.com",
"id": 123456,
"is_active": true,
"permissions": [
"read",
"write"
]
}"#;
let parsed_from_messy: User = from_slice(messy_json).unwrap();
let messy_canonical = to_vec(&parsed_from_messy).unwrap();
println!("\n混乱JSON的规范化输出:");
println!("{}", String::from_utf8_lossy(&messy_canonical));
// 5. 验证不同格式但相同逻辑内容的JSON规范化后是否一致
assert_eq!(canonical_json, messy_canonical);
println!("验证通过 - 不同格式的相同数据规范化后结果一致");
}
使用场景
- 数字签名验证:确保JSON数据在传输过程中没有被篡改
- 数据一致性检查:比较两个JSON数据是否逻辑等价
- 区块链应用:需要确定性序列化的场景
- 数据库存储:确保相同数据产生相同的存储表示
注意事项
- 规范化JSON会改变原始JSON的格式(如空格、键顺序等)
- 浮点数会被统一表示为最简形式
- 所有Unicode字符会被转义为\uXXXX形式
- 时间戳和其他特殊格式需要预先处理
这个库特别适合需要严格JSON数据一致性的应用场景,如密码学签名、数据验证等。