JSON 看起来很简单,直到一个多余的逗号让部署失败。大多数 JSON 错误并不复杂:尾随逗号、单引号、注释,或者括号没有配对。这篇文章讲清楚合法 JSON 的规则、最常见的错误,以及如何快速定位问题。
合法 JSON 允许什么
JSON 的语法非常小:
- 值可以是对象、数组、字符串、数字、
true、false或null。 - 对象的键必须是双引号字符串。
- 字符串必须使用双引号,单引号不合法。
- 数组和对象不能有尾随逗号。
- 注释不属于 JSON 规范。
- 数字不能是
NaN、Infinity或十六进制。
规则严格是有意为之:这样所有语言的 JSON 解析器都能对同一份输入达成一致。
最常见的五种错误
1. 尾随逗号
{
"name": "Ada",
"age": 36,
}
这在 JavaScript 和 JSON5 里合法,但在 JSON 里不合法。删除最后一个属性后面的逗号。
2. 单引号
{ 'name': 'Ada' }
JSON 只接受双引号。手动从 Python 或 JavaScript 复制时很容易出现。
3. 键没有加引号
{ name: "Ada" }
对象的键必须是双引号字符串。这是另一个从 JavaScript 带过来的习惯。
4. 注释
{
// 用户名
"name": "Ada"
}
JSON 不支持注释。如果配置文件需要注释,可以使用 JSONC 或 YAML,但不要给 JSON API 发送注释。
5. 括号不匹配
少一个 } 或 ] 时,错误经常出现在文件末尾,而不是真正出错的位置。格式化文档可以让缺失的层级一眼可见。
为什么要格式化
压缩后的 JSON 对机器高效,对人却很难读。格式化之后:
- 结构一目了然;
- 代码评审里的 diff 更容易看;
- 更容易发现缺失的括号或逗号;
- 两份数据的结构可以直接对比。
调试 API 响应时,先粘贴到格式化工具再读。比较两个版本时,先分别格式化,再做 diff,这样空白噪音会被去掉,真正的变化才会显现。
美化与压缩
美化会加入缩进和换行,便于阅读;压缩会去掉所有可选空白,便于传输。两者是同一份数据,按场景选择:
- 日志、文档、测试数据、调试:使用美化输出。
- 请求体和响应体,体积敏感:使用压缩 JSON。
格式化工具应该允许在 2 空格、4 空格、Tab 和压缩之间切换,同时不改变数据本身。
用行号定位错误
最有用的错误信息不是“JSON 不合法”,而是“第 4 行第 3 列出现意外字符”。现代解析器通常会给出位置,但不同运行时的格式不一样。
浏览器里的格式化工具可以解析文档、报告行号和列号,并在 JSON 合法之前保持输出为空。这个反馈循环比猜括号快得多。
JSON 格式化工具 就是这样工作的:粘贴数据,看到错误位置,解析通过后再格式化或压缩。所有处理都在本地完成,可以放心处理生产数据。
JSON 不是 JavaScript 对象
JavaScript 对象字面量可以包含函数、undefined、单引号键和注释,JSON 都不行。两者语法相似,但 JSON 是一种数据格式,不是编程语言。
把 JSON 变成 JavaScript 值用 JSON.parse;把 JavaScript 对象变成 JSON 用 JSON.stringify,它会:
- 丢弃
undefined和函数; - 把日期转换成字符串;
- 遇到循环引用直接报错;
- 把
NaN和Infinity变成null。
了解这些规则,可以避免一整类“这个字段为什么消失了”的 bug。
转成其他格式
数据合法之后,经常还需要换一种形态:
- JSON 转 CSV 把对象数组变成表格。
- YAML 转 JSON 在两种配置格式之间转换。
- 文本对比 在格式化之后比较新旧两份数据。
实用检查清单
- 先粘贴到格式化工具,修复语法错误。
- 比较两个版本之前,先分别格式化。
- 只在真正发送数据时压缩。
- JSON 里不要写注释;需要注释的配置用 YAML 或 JSONC。
- 不要用 JSON 存放不该出现在日志里的密钥。
JSON 的严格是有意设计的。记住它强制的那几条规则之后,大多数解析错误都能在几秒内定位。