JSON 完全指南:结构、安全陷阱与现代用法

什么是 JSON?

JSON(JavaScript Object Notation,RFC 8259)是一种轻量级的、与语言无关的数据交换格式。它用极简的文本描述结构化数据,既能让人直接读懂,又能被几乎所有编程语言以极低成本解析。今天你打开的每一个 App、调用的每一个 REST API、写入的每一个 NoSQL 文档,背后几乎都在用 JSON 传递数据。

JSON 之所以能击败 XML 成为 Web 时代的事实标准,核心原因只有三个:够简单(六种类型覆盖绝大多数场景)、够严格(没有歧义,解析结果可预测)、够通用(从浏览器到嵌入式设备都有原生支持)。

JSON 的六种数据类型

理解 JSON 的第一步,是记住它只有六种值类型,不会有第七种:

类型

示例

说明

字符串

"oltool"

必须用双引号包裹,支持 \n、\t、\uXXXX 等转义

数字

42、3.14、-0.5

不区分整数与浮点,统一按双精度处理

布尔

true / false

小写,不是字符串

空值

null

表示"有值但为空",区别于"字段不存在"

对象

{"k": "v"}

无序的键值对,键必须是字符串

数组

[1, 2, 3]

有序的值列表,元素可以是任意类型

一个真实世界里的 JSON 往往同时包含这些类型:

{

"user": {

"id": "u_1001",

"name": "彬哥",

"active": true,

"roles": ["admin", "editor"],

"metadata": null

},

"score": 98.5

}

嵌套结构:对象与数组的组合

JSON 的强大之处在于对象可以嵌套对象、数组可以嵌套数组、对象和数组还能互相嵌套。这种组合足以表达任意复杂度的业务数据,而语法始终保持一致:

用对象表达"一条记录的属性"。

用数组表达"一组同构的元素"。

用对象数组表达"一张表"(最常见的 API 返回形态)。

当层级过深时,人的肉眼很难看清结构。开发时建议先用 JSON 格式化 工具把压缩的一行展开成带缩进的树,或用 JSON 树形查看器 折叠浏览;需要把后端返回的大文档转成表格分析时,可以用 JSON 转 CSV。

典型用法:API、配置与存储

1. 接口数据交换。 这是 JSON 的主战场。请求体、响应体、Webhook 回调几乎都是 JSON。它的严格类型让前后端"说什么就是什么",不需要像 XML 那样先约定 schema 才能解析。

2. 配置文件。 从 package.json 到 tsconfig.json,Node 生态把 JSON 当成默认的声明格式。需要人工频繁编辑的配置则更常写成 YAML,再在构建期转成 JSON 给程序消费——可借助 YAML 转 JSON 与 JSON 转 YAML 互转。

3. 文档型存储。 MongoDB、DynamoDB、RedisJSON 等直接用 JSON 文档建模数据,字段可以随记录灵活增减,特别适合 schema 演进快的场景。

与 XML / YAML / MessagePack 的取舍

维度

JSON

XML

YAML

MessagePack

可读性

一般

最好

差(二进制)

解析速度

最快

注释支持

体积

最小

典型场景

API / 存储

遗留系统 / SOAP

人工配置

高性能二进制传输

结论很直接:机器之间高频交换选 JSON,人工写的配置选 YAML,极限性能/带宽场景选 MessagePack(底层仍是 JSON 的语义)。XML 如今主要在银行、电信等遗留系统里出现,新项目很少主动选择。

高频踩坑点(务必注意)

1. 大数精度丢失

这是最隐蔽、最致命的坑。JSON 没有整数类型,所有数字都按 IEEE 754 双精度浮点解析。超过 2^53(约 9007 万亿)的整数无法被精确表示——典型受害者是 64 位雪花 ID、数据库自增主键、身份证号。一旦在 JavaScript 里 JSON.parse,大整数会被悄悄四舍五入成近似值,且不会报错。

防御:跨语言传输大整数时优先用字符串;前端需要用 JSON.parse 的 reviver 配合 BigInt,或使用支持大数的解析库。

2. 末尾逗号与引号

JSON 比 JavaScript 严格:对象/数组最后一个元素后面不能有逗号,键必须用双引号(单引号非法),字符串内部的双引号必须转义为 \"。这些在浏览器控制台里能跑的写法,到了标准 JSON 解析器里全部报错。

3. 字符串里的换行与不可见字符

从 Excel、 Word 或网页文本框复制进 JSON 的多行文本,常常夹带真实的换行符、制表符或 BOM。标准 JSON 要求字符串里的换行必须写成 \n,原始换行会直接让解析失败。提交前用格式化工具做一次清洗和校验能省掉大量调试时间。

4. 循环引用与函数

JSON.stringify 遇到循环引用的对象会直接抛 TypeError;它也会自动丢弃函数、undefined 和 Symbol。如果你的数据里混入了这些类型,序列化结果会和预期悄悄不一致——尤其是把前端状态整体转 JSON 时极易中招。

5. JSON 注入

把不可信的用户输入直接拼进 JSON 字符串(而不是用 JSON.stringify),或在前端用 eval / JSON.parse 解析来路不明的字符串,都可能引发注入。始终用标准序列化/解析 API,并对外部输入做校验。

现代工作流建议

写:用 TypeScript 时,把示例 JSON 直接喂给 JSON 转 TypeScript 生成接口类型,避免手敲 schema 出错。

查:用 JSONPath 查询 从深层文档里精确提取字段,比肉眼翻层级高效得多。

验:上线前用 JSON 格式化/校验 跑一遍,定位语法错误的具体行列号。

换:跨格式用 JSON 转 XML、JSON 转 TOML、Excel 转 JSON 等工具批量转换,不必手写脚本。

所有这些操作都能在码屋(Mawu)的在线工具里本地完成——数据只存在于你的浏览器,不上传任何服务器,断网也能用。

小结

JSON 看似简单,却是现代软件最重要的"通用语"。掌握它的六种类型与嵌套规则只是起点,真正拉开差距的是对精度陷阱、严格语法、注入风险的警惕。把它当成一个需要被尊重和校验的契约,而不是随手拼的字符串,你的接口和配置会少掉一大类诡异 bug。