使用serde/serde_json反序列化时如何保留原始JSON字符串载荷?
serde_json反序列化保留完整原始JSON的实现方案
现有方案的问题
你当前采用的先转Value再序列化的方案有两个明显缺陷:
- 存在额外的序列化/反序列化开销,数据量大时性能损耗明显
- 序列化
Value得到的字符串和原始输入不一致,会丢失原始的格式(空格、换行、字段顺序),不符合保留原始JSON的需求
最优实现方案
方案1:基于RawValue手动实现反序列化(推荐)
这个方案完全内置在反序列化流程中,自动保留原始JSON的所有格式,不需要外部手动传递原始字符串,同时适配普通字符串、流两种反序列化场景:
use serde::de::Deserializer; use serde::{Deserialize, Serialize}; use serde_json::value::RawValue; #[derive(Debug, Serialize)] struct User { pub raw: String, pub id: u64, pub login: String, } impl<'de> Deserialize<'de> for User { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { // 读取整个JSON对象的原始字符串,几乎无性能开销 let raw_json = <&'de RawValue>::deserialize(deserializer)?; // 反序列化其他业务字段 #[derive(Deserialize)] struct UserInner { id: u64, login: String, } let inner: UserInner = serde_json::from_str(raw_json.get()) .map_err(serde::de::Error::custom)?; Ok(Self { raw: raw_json.get().to_string(), id: inner.id, login: inner.login, }) } }
使用方式和普通反序列化完全一致:
let json_str = r#"{ "id": 123, "login": "johndoe" }"#; let user: User = serde_json::from_str(json_str).unwrap(); // user.raw 就是完全和输入一致的原始JSON字符串
方案2:辅助函数封装(轻量适配)
如果你已经持有原始JSON字符串,不需要适配流反序列化场景,可以用更简单的辅助函数实现,无需修改结构体的默认派生逻辑:
#[derive(Debug, Serialize, Deserialize)] struct User { #[serde(skip)] pub raw: String, pub id: u64, pub login: String, } fn deserialize_user(json_str: &str) -> Result<User, serde_json::Error> { let mut user: User = serde_json::from_str(json_str)?; user.raw = json_str.to_string(); Ok(user) }
这个方案代码量最少,没有任何额外性能开销,适合绝大多数普通场景使用。
内容的提问来源于stack exchange,提问作者Evaldas Buinauskas
相关产品推荐
相关产品推荐

