← 返回文章列表

JSON 总是报错?90% 的人栽在这 4 个细节

JSON避坑

JSON 与 JS 对象不是一回事

JSON 是数据交换格式,比 JavaScript 对象字面量严格得多:键必须用双引号、字符串必须用双引号、不允许注释、不允许尾逗号。很多报错都源于把 JS 对象的写法直接搬进了 JSON。

高频错误清单

  • 尾逗号:[1, 2, 3,] 末尾多一个逗号;
  • 单引号:{'name': 1} 应为双引号;
  • 键没加引号:{name: 1} 键必须写成 "name";
  • 注释:// 与 /* */ 都不合法。

快速排查思路

  1. 看报错信息里的行号列号,多数解析器会直接指出出错位置;
  2. 检查报错行的上一行:缺逗号或多逗号是常见根源;
  3. 字符串内含双引号要转义为 ";
  4. 拿不准就先格式化一遍,缩进结构清晰后逐段检查。

格式化与压缩

开发时用格式化(2 空格缩进)便于阅读,传输时用压缩减少体积。含敏感数据的 JSON 建议在本地工具处理,不要贴到不可信的在线服务。

合法与非法写法对照

部分JS 对象字面量合法 JSON
键{name: 1}{"name": 1}
字符串'abc'"abc"
尾逗号[1, 2,][1, 2]
注释// 说明不支持
特殊值undefined、NaN只能用 null

代码示例:安全地解析

// 不要直接 parse 不可信输入,包一层错误处理
function safeParse(text) {
  try {
    return { ok: true, data: JSON.parse(text) };
  } catch (e) {
    // e.message 通常带位置提示,例如 "Unexpected token } in JSON at position 42"
    return { ok: false, error: e.message };
  }
}

// 命令行校验与格式化(jq)
// jq . data.json     → 校验并美化输出
// jq -c . data.json  → 压缩为单行

JSON、YAML、TOML 怎么选

  • JSON:机器间交换的事实标准,不支持注释与多行字符串,适合 API 与程序生成的配置;
  • YAML:可读性好、支持注释,适合人工维护的配置,但缩进敏感、隐式类型坑多;
  • TOML:语义明确、不易歧义,适合项目配置文件(如 Cargo.toml、pyproject.toml)。

延伸问题

大 JSON 卡顿怎么办?先压缩体积、只取需要的字段(jq '.items[] | {id, name}'),必要时改用流式解析。JSON 会保留字段顺序吗?规范不保证顺序,依赖顺序的场合请在消费端显式排序。

实战案例:三个排查场景

  1. “接口偶发报 JSON parse error”:多半是响应里混入了 HTML 错误页或 BOM 头。先看原始文本,而不是只信控制台。
  2. “大整数 ID 少了末尾几位”:JavaScript 数字精度约 2^53,19 位订单号解析后会失真。修复:以字符串处理大整数。
  3. “注释一加就报错”:标准 JSON 不允许注释,报错是正常的,别在配置文件里随手加 //。

常见问题(FAQ)

格式化和压缩会改数据吗?不会,只动空白与缩进。重复键以哪个为准?解析时通常取最后一个,容易埋雷,应尽早发现。JSON 和 JSON5 什么区别?JSON5 允许注释、单引号与尾逗号,但通用解析器不认,别把 JSON5 当 JSON 用。怎么找语法错误位置?用带行列提示的格式化/校验工具,比肉眼找逗号快得多。

动手试试:JSON 格式化

大文件与流式解析

  • 避免整体载入:几 MB 以上的 JSON 用流式解析器(如 SAX 风格)逐事件处理,不要一次 JSON.parse 整个字符串;
  • 先取结构再取内容:大文件先只解析出顶层键与数组长度,确认结构正确后再决定是否全量处理;
  • 注意 BOM:带 UTF-8 BOM 的文件直接解析会报错,读取时应显式剥除;
  • 不要用正则改 JSON:用正则替换字段极易破坏转义与嵌套结构,应解析后修改再序列化。

格式与可读性约定

团队内应固定缩进与键顺序规则:缩进统一 2 空格;键顺序要么按业务含义固定,要么在提交前排序,避免每次 diff 都因顺序变化而失真。格式化应在保存或提交阶段自动完成,而不是靠人工记得执行。

数字与精度陷阱

JSON 规范不区分整数与浮点,1.0 与 1 在多数解析器中会归一化;而 ID、金额这类必须精确的值很容易在中间环节被当成数字而丢精度。约定上,超过 2^53 的整数与货币金额一律用字符串传输。