使用serde_json传输Vec<u8>时,base64编码能否节省空间?
问题分析与解决方案
为什么字节数会膨胀三倍?
你猜的方向没错,但更准确的原因是:serde_json默认会把Vec<u8>里的每个字节序列化为十进制数字字符串。比如单个字节0xFF会被转成字符串"255",占3个UTF-8字节;哪怕是小数值如0x01,也会变成"1"占1字节,平均下来每个字节会占用2-3个字符,400字节的原始数据自然会膨胀到1200左右,正好是三倍的量级。
你用serde_bytes没效果,大概率是没给Vec<u8>字段加上对应的序列化注解——默认情况下serde_bytes不会自动接管Vec<u8>的序列化,还是会按普通JSON数组处理,字节数自然还是一样膨胀。
你的字节统计方式是对的
serde_json::to_value(content).to_string().to_bytes().len()这个统计逻辑是准确的:因为最终通过reqwest发送JSON时,传输的就是这个序列化后的UTF-8字符串的字节数,完全能反映实际请求的大小,用来预判接口限制没问题。
可行的解决方案
1. 用Base64编码(推荐)
这是二进制数据在JSON里传输的标准做法,开销远低于原生数组序列化。你可以用serde_with库的Base64注解自动处理序列化和反序列化,不用手动转:
use serde::{Deserialize, Serialize}; use serde_with::serde_as; use serde_with::base64::Base64; #[serde_as] #[derive(Serialize, Deserialize)] struct MyRequest { #[serde_as(as = "Base64")] content: Vec<u8>, } // 序列化时自动转base64,反序列化自动转回Vec<u8> let req = MyRequest { content: vec![0u8; 400] }; let json_str = serde_json::to_string(&req).unwrap(); println!("Serialized length: {}", json_str.as_bytes().len()); // 约500字节左右
这样既解决了字节膨胀问题,又省去了手动处理编码解码的繁琐步骤。
2. 正确使用serde_bytes(不推荐,字节开销仍大)
如果坚持要用JSON数组形式,得给Vec<u8>加上serde_bytes的注解,让它按优化后的逻辑序列化数字数组,但本质还是每个字节转成字符串形式,字节数还是会膨胀到1200左右,对你的接口限制来说没帮助,所以不推荐:
use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] struct MyRequest { #[serde(with = "serde_bytes")] content: Vec<u8>, }
内容的提问来源于stack exchange,提问作者NoKey
相关产品推荐
相关产品推荐

