尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

JSON序列化与反序列化:原理、实战踩坑与安全防范全攻略

JSON序列化与反序列化:原理、实战踩坑与安全防范全攻略 搞后端开发的谁没被 JSON 折磨过几个晚上。序列化、反序列化这六个字看起来简单真落到项目里中文变 \u、日期格式对不上、字段映射不上、性能卡顿甚至整个服务被反序列化漏洞搞挂各种坑我基本都踩过一遍。这篇就围绕“JSON序列化反序列化”这个主题把原理、实操、踩坑和安全问题一次说透。我打算从四个维度展开先搞清楚序列化到底在干嘛为什么需要它然后分语言过一遍最常见的实战写法各个语言的坑也会随手点出来再往后是复杂场景比如中文、日期、字段映射、循环引用这类高频问题最后聊聊性能选型和反序列化安全这块是很多人的盲区但其实非常重要。每个部分我都会给可直接抄作业的代码和配置也会标注哪些地方是实际操作中容易翻车的点。顺便说一句下面的内容会涉及 Python、Java、JavaScript、Go 四种常见语言的示例不管你是做 Web 接口、写中间件还是搞数据同步都能找到用得上的东西。如果你只是想快速定位某个报错建议直接跳到第 6 部分的常见问题速查表。1. 序列化与反序列化究竟在解决什么问题1.1 内存对象与字符串格式之间隔着一道“翻译”当你用 Python 写了一个dict比如{name: 张三, age: 18}它在内存里有自己的存储结构有类型、有引用、有嵌套。但如果你想把它传给另一个程序、存进 Redis、写入消息队列、返回给前端就没法直接把这坨内存结构原样丢出去了。不同语言、不同进程甚至同一程序的不同时期对内存里对象布局的理解都不一样。这时候就需要一种“通用语言”来翻译。JSON 就是一种通用语言。它本身是纯文本格式任何语言都能读写。把一个内存对象转换成一串符合 JSON 语法规则的字符串这个动作就是序列化反过来把这串字符串解析回有类型、有结构的内存对象就是反序列化。你可以把序列化理解为把乐高拼好的模型拆开然后写一份图纸反序列化就是按图纸重新拼回模型。图纸本身不关心模型是什么样的只要图纸画得标准谁都能照着拼出来。1.2 JSON 为什么能成为事实标准而不是 XML 或二进制早些年 XML 也在做这件事而且做得相当重。XML 有属性、有命名空间、有 DTD 校验功能强大但也烦琐。一条简单的数据在 XML 里可能要写小半屏标签。二进制的序列化方案比如 Java 原生的ObjectOutputStream、Python 的pickle速度快但有个致命问题只能在相同语言、相同版本之间使用跨语言就成了摆设。JSON 能胜出靠的是三个朴素的特点可读性强。数组、对象、键值对的结构一眼能看懂出了问题能直接肉眼排查。跨语言。几乎每一种现代语言都有官方的 JSON 解析库接收端不用关心发送端用什么语言写的。轻量。没有复杂的标签和声明数据密度高传输和存储成本低。所以很多场景里我们默认不是“要不要用 JSON”而是“用什么库去解析 JSON 更顺手”。1.3 一个容易被忽略的点序列化不等于“拼字符串”有些新人会想JSON 不就是{a: 1}这样的文本吗我手动拼字符串也能造出来。真出了问题之后就会发现手动拼 JSON 是灾难的开始。缩进、逗号、引号、中文转义、嵌套层级任何一处出错都可能导致解析失败而且手动拼出来的字符串没法保证严格符合 JSON 规范。更关键的是手动拼字符串意味着你在序列化过程中绕过了类型检查。一个数字被拼成了字符串、一个空值被拼丢了、一个布尔值被拼成了字符串true这些问题很难被一眼发现。所以凡是正经项目所有序列化操作都必须交给标准库或成熟的第三方库你要做的只是选择合适的库和合适的配置。2. 四种主流语言的 JSON 实战玩法2.1 Pythonjson模块的常规操作与编码陷阱Python 的json模块是最常用的语法简洁但你如果不对参数做一些处理很容易在“中文”这个点上踩坑。import json data { name: 张三, scores: [88, 92, 76], meta: {grade: 初二, class: 3} } # 直接序列化你会发现中文变成了 \u5f20\u4e09 这类转义序列 json_str json.dumps(data) print(json_str) # {name: \u5f20\u4e09, scores: [88, 92, 76], ...} # 加上 ensure_asciiFalse 之后中文就会原样保留 json_str_cn json.dumps(data, ensure_asciiFalse, indent2) print(json_str_cn)实际操作里我几乎总是会加ensure_asciiFalse尤其是做接口返回给前端看的时候返回一串\u5f20\u4e09虽然功能上没问题但排查问题的时候又得做一次解码多一道步骤就多一分烦躁。indent2只是为了人类阅读方便如果对存储空间有追求可以不加。反序列化同样简单json_str {name: 张三, scores: [88, 92, 76]} data json.loads(json_str) print(data[name]) # 张三 # 需要注意load 从文件读取loads 从字符串读取这里有个细节值得提醒json.load和json.loads差一个 s用法完全不同。json.loads接收的是字符串json.load接收的是文件对象。命名很接近非常容易用混我之前就有过把字符串传给json.load导致报错AttributeError的经历。2.2 JavaJackson 才是首选fastjson 要谨慎Java 这边的选择比较多Gson、fastjson、Jackson各有拥趸。我的观点是新项目一律优先 Jackson。原因后面单独讲安全的时候会展开这里先看用法。用 Jackson 序列化一个 Java 对象import com.fasterxml.jackson.databind.ObjectMapper; public class User { private String name; private int age; // 必须有 getter/setter或者用 JsonProperty 注明字段名 } ObjectMapper mapper new ObjectMapper(); User user new User(张三, 18); // 序列化为字符串 String json mapper.writeValueAsString(user); System.out.println(json); // {name:张三,age:18} // 反序列化为对象 User parsed mapper.readValue(json, User.class);这里有一个必须掌握的细节Jackson 默认依赖 getter 方法来完成序列化依赖无参构造器和 setter 方法或字段来完成反序列化。如果你的类没写 getter或者只写了有参构造器常见报错就是InvalidDefinitionException: Cannot construct instance of ...。这时候不要怀疑是 JSON 格式错了先检查类的默认构造器是否存在。如果你在 Spring Boot 里做 Web 接口ObjectMapper已经由框架帮你配置好了直接在 Controller 里接收 JSON 请求体即可PostMapping(/user) public User createUser(RequestBody User user) { // RequestBody 会自动完成 JSON 到对象的转换 return user; }2.3 JavaScriptJSON.parse和JSON.stringify的对称之美前端这边的 JSON 操作就更简单了原生就支持几乎没有任何学习成本。需要注意的是数字精度和undefined的处理。const obj { name: 张三, age: 18, tags: [前端, 后端] }; // 序列化注意结果是字符串 const str JSON.stringify(obj); console.log(str); // {name:张三,age:18,tags:[前端,后端]} // 反序列化 const back JSON.parse(str); console.log(back.name); // 张三有几个坑提醒一下如果对象里有undefined、函数、SymbolJSON.stringify会直接忽略这些属性结果里不会出现。如果数组里有undefined会被转成null。如果数字太大比如超过Number.MAX_SAFE_INTEGER9007199254740991精度会丢失。这类数据常见于雪花算法生成的 ID一定要在后端转成字符串再返回。const bigData { id: 1762999336676802561 }; console.log(JSON.stringify(bigData)); // 原来的 1762999336676802561 变成了 1762999336676802600精度已经丢了这个精度问题我印象特别深跟第三方对接接口时雪花 ID 莫名变了尾部几位排查了半天才发现是前端JSON.parse的时候就已经丢失精度了后端怎么修都白搭。2.4 Go结构体 Tag 是 JSON 映射的灵魂Go 的encoding/json标准库用得很多关键是结构体的jsontag。package main import ( encoding/json fmt ) type User struct { Name string json:name Age int json:age Tags []string json:tags,omitempty hidden string // 小写字段JSON 序列化时会被忽略 } func main() { user : User{Name: 张三, Age: 18, Tags: []string{go, json}} data, _ : json.Marshal(user) fmt.Println(string(data)) // {name:张三,age:18,tags:[go,json]} var parsed User _ json.Unmarshal(data, parsed) fmt.Println(parsed.Name) // 张三 }这里有两个值得关注的点。第一个是omitempty它表示当字段是零值空字符串、0、空数组、nil时序列化结果中省略这个字段。如果你不想省略就别加。第二个是字段可见性Go 的 JSON 序列化只能处理导出的字段大写字母开头小写字段一律不参与序列化。这是一道经典的 Go 面试题同时也是新手最容易困惑的地方——结构体里写了字段序列化后却发现丢了。3. 复杂场景中文、日期、字段映射和循环引用3.1 中文编码别让\u5f20\u4e09毁掉排查效率第 2 节提到 Python 的ensure_asciiFalse其实其他语言也有类似调整。例如 Java 的 Jackson默认情况下并不会对中文转义中文会原样输出。但如果你用的是 Spring Boot 默认配置发送 HTTP 请求时如果 Content-Type 没有带对charsetUTF-8就可能出现中文乱码。这个问题不单单是 JSON 的问题而是 HTTP 编码的问题。我的习惯是接口层统一在响应头里显式声明Content-Type: application/json;charsetUTF-8并且在序列化配置里把编码强制为 UTF-8。不要依赖“默认”编码因为在不同的部署环境里默认编码并不可靠。3.2 日期时间格式反序列化场景中最容易不一致的字段前后端对时间的处理方式差异很大后端可能是个java.time.LocalDateTime前端可能想接收2025-01-15 14:30:00。如果不做配置Jackson 默认会把这个字段序列化成时间戳或奇怪的数组格式两边直接对不上。合理的做法是全局配置一下日期格式ObjectMapper mapper new ObjectMapper(); // 关闭时间戳输出改用字符串 mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // 设置统一格式 mapper.setDateFormat(new SimpleDateFormat(yyyy-MM-dd HH:mm:ss));如果是 Java 8 的LocalDateTime还需要注册JavaTimeModuleObjectMapper mapper new ObjectMapper(); mapper.registerModule(new JavaTimeModule());在 Python 里datetime对象无法直接用json.dumps序列化会报TypeError: Object of type datetime is not JSON serializable。解决办法是写一个自定义的转换函数import json from datetime import datetime def default_serializer(obj): if isinstance(obj, datetime): return obj.strftime(%Y-%m-%d %H:%M:%S) # 其他自定义类型可以继续在此扩展 raise TypeError(fType {type(obj)} not serializable) now datetime.now() json_str json.dumps({time: now}, defaultdefault_serializer) print(json_str) # {time: 2025-06-18 14:30:00}这类日期格式问题说穿了就是“约定优先”。项目一开始就应该在文档里约定好时间字段的格式和时区而不是等联调的时候两边互相甩锅。3.3 字段名不一致用映射而不是硬改类结构对接第三方接口时对方返回的字段可能叫user_name你 Java 类里字段叫userName或者 Python 的dict里是user-name这么不规范的也有。这时候第一个想到的应该是映射机制。Jackson 用JsonPropertypublic class UserDTO { JsonProperty(user_name) private String userName; }Go 用前面提到的jsontagtype UserDTO struct { UserName string json:user_name }Python 没有内置的 JSON 字段映射机制但json.loads之后把键重建一次即可或者用dataclasses加__post_init__处理再优雅一点可以用bidict做双向映射import json raw {user_name: 张三} data json.loads(raw) # 简单的键名转换 converted { userName: data[user_name] }永远不要为了迎合第三方 JSON 字段故意把类字段命名成不规范的样子。那会让内部代码被外部格式绑架时间长了谁也受不了。3.4 循环引用序列化器最害怕的“牵手”对象考虑这样一个简单的情况A类里有个字段是B类型B类里又有个字段回指A类型。这时候如果直接序列化A序列化器会陷入无限递归A 里面有 BB 里面有 AA 里面又有 B……直到栈溢出报错。Python 的表现是循环引用错误ValueError: Circular reference detectedJava 的 Jackson 可能会直接栈溢出。解决办法有这么几种路径在字段上标记忽略比如 Jackson 的JsonIgnore明确告诉序列化器这个字段不用管。使用JsonManagedReference和JsonBackReference处理父子关系。再造一个专用的 DTO只保留你需要传输的字段彻底屏蔽掉循环结构。我自己遇到过的最难缠的场景是 ORM 框架查询出来的实体类比如一对多关系父对象里包含子对象列表子对象又引用父对象。解决方案一般是上述第 3 种Slave 表转 DTO。这不只解决了序列化问题也让接口层不直接暴露数据库实体结构安全性更好。4. 性能、工具选型与 Redis 序列化配置4.1 序列化性能到底重不重要该怎么测如果是普通业务接口一天几万次调用用哪个 JSON 库其实无所谓性能差异可能在毫秒级以下。但如果你在做网关、大数据管道、消息中间件这类高吞吐组件性能就会成为一票否决项。序列化性能的衡量维度有三个速度、内存占用、产物大小。速度影响吞吐内存占用影响 GC产物大小影响网络带宽和存储成本。正常的测试方法是造一批包含嵌套对象、数组、字符串的复杂数据分别用不同库跑一万次统计耗时和结果大小。实际项目中我的建议是不要过早优化。先用项目语言里最主流的库把功能做对然后在压测阶段用 profiler 找出热点再考虑要不要换库。很多人的性能问题根本不是序列化带来的而是做了大量重复的序列化和反序列化操作。4.2 主流 JSON 序列化库的横向对比下面这个表格是我在不同项目中实测后的个人感受不是权威基准仅供参考语言库特点适用场景JavaJackson功能全面Spring 默认扩展性强绝大多数后端项目首选JavaGson轻量API 简洁小项目、Android 端Javafastjson速度快但历史漏洞多老项目维护新项目不推荐Pythonjson标准库简单可靠大多数场景默认选择Pythonorjson速度比标准库快约 5 倍高并发接口、大数据处理Goencoding/json标准库简单、无依赖默认选项Gojsoniter兼容标准库性能更高对性能有追求的中间件JavaScriptJSON原生浏览器自带无需引入前端几乎唯一选择有一个点必须强调fastjson 在 Java 里确实做得非常早性能也一直不错但历史上的反序列化漏洞数量太多很多安全团队直接把它列为禁用库。如果一个项目还在大量使用 fastjson至少应该升级到最新版本并补上autotype限制配置。4.3 Redis 的序列化配置这个坑值得单独拿出来讲redisTemplate存储乱码的问题大多数用 Spring Boot Redis 的开发者都遇到过。存入 Redis 的 key 和 value 经常是\xac\xed\x00\x05t\x00开头的一堆乱码原因就是默认的JdkSerializationRedisSerializer把 Java 对象序列化成了二进制内容还带上了 Java 序列化头的\xac\xed标志。正确的配置方式是改用 JSON 序列化器Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); // key 使用 String 序列化器避免 key 变成乱码 StringRedisSerializer stringSerializer new StringRedisSerializer(); template.setKeySerializer(stringSerializer); template.setHashKeySerializer(stringSerializer); // value 使用 JSON 序列化器 Jackson2JsonRedisSerializerObject jacksonSerializer new Jackson2JsonRedisSerializer(Object.class); // 这里需要配置 ObjectMapper 的反序列化默认类型否则 List、Map 等类型转换会出问题 ObjectMapper om new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); jacksonSerializer.setObjectMapper(om); template.setValueSerializer(jacksonSerializer); template.setHashValueSerializer(jacksonSerializer); template.afterPropertiesSet(); return template; } }这里容易出问题的是activateDefaultTyping。如果不开启默认类型信息反序列化时 Jackson 并不知道 JSON 字符串要还原成什么具体的类因为Object.class本身太宽泛了。开启默认类型后会在 JSON 里加一个类型标识字段虽然数据看起来没那么干净但反序列化能正常工作。另外要注意Jackson2JsonRedisSerializer与GenericJackson2JsonRedisSerializer在类型处理上有些差异。前者更灵活后者更省心。如果存取的数据类型比较固定建议直接用GenericJackson2JsonRedisSerializer更稳妥一些。还有一个实际经验如果 Redis 里存的 value 是纯字符串其实完全用不上序列化器直接用StringRedisTemplate就行。只有当 value 是对象、列表、Map 这类结构化数据时才需要 JSON 序列化器。5. 反序列化安全这不是安全工程师一个人的事5.1 为什么反序列化会成为攻击入口反序列化的本质是根据一段数据来重建对象这个过程中如果目标类里有可以被恶意构造的“魔法方法”比如 Java 的readObject或某些类的setter、getter攻击者就可以通过精心构造的 JSON 数据让目标类在反序列化过程中执行攻击者期望的操作最终实现任意类加载甚至远程命令执行。这就是反序列化漏洞的原理。需要注意它不一定发生在 Java。Python 原生的pickle模块如果用来反序列化不可信数据也是极其危险的因为 pickle 本质上就是“任意代码执行”的载体。相比之下json.loads要安全得多因为它只做纯数据解析不触发对象构造。JSON 本身是安全的不安全的是“把 JSON 反序列化成对象”这个过程。5.2 fastjson 的教训和最小化原则fastjson 之所以被安全圈盯上是因为为了追求“极致的便捷”它允许在 JSON 里指定类名由调用方决定要实例化哪个类。攻击者如果能控制类名就相当于拿到了一份菜单里面都是能“帮忙执行命令”的类。现在虽然官方也不断收紧、修复、加黑名单但这类设计层面的风险很难根除。所以我的建议很简单新项目一律不要用 fastjson老项目能换就换不能换则必须升级到修复版本并且至少做到两点关闭AutoType或启用safeMode。永远不要反序列化来自客户端、消息队列、第三方接口的不可信 JSON 到具体业务类除非你能完全控制这个类及其依赖。经常有同学问“这个方法行不行那个方案行不行”。我统一回答最稳妥的方案不是用某个“安全配置”而是压根不要让不可信数据走对象反序列化这条路。把 JSON 解析成Map、List这种基础数据结构再从里面取值做白名单校验风险就降到极低。5.3 常见的反序列化攻击路径与防御策略这里不深入攻击节奏只从防御视角说清楚几个原则。第一类的readObject、readResolve或类似构造钩子一定不要直接依赖不可信数据。第二在反序列化入口设置类型白名单只允许预定义的类型被还原。第三应用层接口的统一异常处理里不要把反序列化异常的堆栈信息原样返回给调用方避免泄露类名、依赖库版本、Java 版本这些敏感信息。本质上反序列化安全问题的本质是“信任了不该信任的数据”。只要你理解了这一点就会明白为什么安全团队对 fastjson、对 Java 原生序列化这么警惕——问题往往不是库本身而是使用方式。5.4 对 ViewState 这类服务端状态反序列化的一点提醒ASP.NET 的 ViewState 如果开启了加密和签名应该不会有问题。但这个机制一旦配置错误比如私钥泄露、或开发环境用固定密钥、或未强制校验签名攻击者就可能篡改 ViewState 数据。这类问题说到底还是同一个逻辑任何包含“数据还原对象”逻辑的入口都必须当成攻击面来对待。建议所有开发者尤其是后端至少了解一下这类机制的存在与风险这是安全的底线思维。测试这类问题通常也是安全扫描的一部分比如用一些渗透测试工具去模拟构造畸形数据观察目标程序是否会异常。对于开发同学来说最要紧的是任何反序列化入口都要接异常捕获并且不要让程序因为一条异常数据就整体崩溃。6. 高频报错与排查技巧实录6.1 “Failed to deserialize the JSON body into the target type”这类报错最常见于 .NET 或 Java 的接口层。核心原因是 JSON 数据与目标类型不一致常见细节有三种缺少必填字段比如目标类型里有非空属性但 JSON 里没有。类型不匹配比如 JSON 里是字符串18目标属性是int。大小写不匹配比如 JSON 里是UserName目标属性是userName且配置了严格区分大小写。排查思路很简单把抛出的异常信息里指到的那个字段名和类型挑出来跟请求体 JSON 逐一对一下哪个对不上就是哪个。多数情况下问题不是库有 bug而是字段对不上。6.2json.loads报 JSONDecodeError注意多余的空格和 BOM 头Windows 环境下保存的 JSON 文件经常带一个 BOM 头\ufeff直接json.load会得到JSONDecodeError。解决办法是先按 UTF-8 with BOM 或 UTF-8-sig 编码读取再解析with open(data.json, r, encodingutf-8-sig) as f: data json.load(f)另外从 Excel 或某些旧系统导出的 JSON 文件里键和值之间可能会有全角空格、全角引号。这看起来是 JSON解析的时候却完全不认建议先复制进编辑器里检查。字符编码这类问题经验和“检查文件二进制内容”比读报错更有效。6.3 反序列化之后字段值是 null八成是私有字段或 getter 问题在 Java 里最常见的情况是实体类字段为私有没有 getter 和 setter或者字段名拼写与 JSON 里的不一致Jackson 只能静默地给出 null 值。这类 bug 比较隐秘因为它不报错只有数据使用的时候才发现是 null。排查方式很简单配置ObjectMapper的FAIL_ON_UNKNOWN_PROPERTIES和FAIL_ON_EMPTY_BEANS让它在无法映射时抛出异常而不是默默返回 null。ObjectMapper mapper new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true); mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, true);同样Go 这边如果字段名是小写反序列化的结果里就是零值。排查思路是一致的先看字段是否导出再看 tag 是否正确。6.4 Java 原生序列化的\xac\xed乱码问题在排查 Redis 乱码时如果一个 value 是以\xac\xed开头基本可以断定是 JDK 原生的ObjectOutputStream序列化产物也就是JdkSerializationRedisSerializer的默认行为。第 4 节已经给了 JSON 序列化的配置方案这里不再重复。只想强调一句出现了这类乱码不要先怀疑编码设置先检查你用的 RedisTemplate 的 key/value 序列化器是什么。6.5 速查表我整理的 JSON 问题快速定位清单现象可能原因推荐排查方向中文变成 \uXXXX序列化参数没关 ASCII 转义设置 ensure_asciiFalse 或等价配置接口返回中文乱码编码非 UTF-8检查 Content-Type charset 和部署环境编码反序列化得到 null字段无 getter/setter、名称不匹配、大小写不一开启 FAIL_ON_UNKNOWN_PROPERTIES 抛错精度丢失数字超过 JS 安全整数范围让后端把长整型 ID 转字符串返回日期变成数字时间戳输出未关闭配置日期格式或禁止时间戳输出循环引用报错双向引用未处理用 DTO 或 JsonIgnore 隔离从文件读 JSON 报错BOM 头或非 UTF-8 编码用 utf-8-sig 或二进制检查头部Redis 里一堆 \xac\xed使用的是 JDK 序列化器改用 JSON 序列化器JSON 数据正常但反序列化失败字段类型不匹配或多了未知字段逐个字段对比启用严格模式6.6 通用排查思路从报错信息里定位蛛丝马迹发现 JSON 相关的问题我一般的排查顺序是先看异常堆栈里指到的类名和字段名再看原始 JSON 字符串记录一下 key 的拼写然后确认目标类型的结构最后检查序列化器有没有特殊配置。这套顺序看起来简单但能解决 90% 的日常问题。还有一个很实用的小技巧在开发环境做个全局异常处理把反序列化失败时的原始报文记录到日志里。生产环境一旦出问题没有原始报文很多东西都无从查起。这个东西平时用处不大关键时刻是救命稻草。最后再分享几个实在的工具和习惯序列化和反序列化本身不难难的是“格式约定”和“边界处理”。我个人习惯是每个团队或项目维护一份简短的“数据交换规范”里面写清楚日期格式、ID 精度、空值策略、字段命名风格以及禁止反序列化来源不明的 JSON 到自定义对象。这份规范三页纸就够了但能省掉不少互相甩锅的联调时间。另外在 IDE 里装一个 JSON 格式化插件在调试接口时配合日志做格式化查看效率会高很多。很多问题一眼看不出格式化之后字段串位的情况就无处遁形了。如果你正在纠结要不要用某个序列化库我的建议是先想清楚三个问题这个库的安全历史如何它在团队内的熟悉度如何它的序列化产物是否便于排查问题。这三个问题比单纯的性能指标重要得多。JSON 这个格式出现到今天已经有快二十年了看起来平平无奇但它的稳定生态和跨语言能力确实让开发者的工作简化了很多。把它用熟练理解它背后数据与对象转换的边界遇到问题时不慌不乱一步步排查这套基本功在任何语言、任何项目里都能复用。
返回列表