JSON 格式化与校验

格式化、校验并查看 JSON——报错会精确指到出错的那个字符。

输出
{
  "name": "jaguar",
  "speed_kph": 80,
  "habitats": [
    "rainforest",
    "wetland"
  ],
  "conservation": {
    "status": "Near Threatened",
    "assessed": 2016
  },
  "nocturnal": null
}

JSON 有效

大小
145 B
压缩后
145 B
节省
0%
键数
7
对象数
2
最大深度
3

四个常见错误

几乎每一份被拒绝的文档,都栽在同样那么几个原因上,而这四个全都是 JavaScript 会接受的东西。陷阱就在这里:JSON 看起来像 JavaScript 的对象字面量,实际上是它一个严格得多的子集。

写法问题正确写法
{"a": 1,}多余的尾逗号{"a": 1}
{'a': 1}用了单引号{"a": 1}
{a: 1}键名没加引号{"a": 1}
{"a": 1} // note写了注释删掉它

还有两个,栽的人少一些,但更难发现。NaNInfinityundefined 都是合法的 JavaScript 值,而它们没有一个是 JSON 值——替代品是 null 或者一个字符串。另外,字符串里出现字面的换行是非法的;它必须写成 \n 这两个字符。

这个校验器如何报告错误

值得一说,因为这正是选用某个格式化工具而不是另一个的理由。成功路径用的是浏览器自带的 JSON.parse,但描述失败时不用它:它的报错格式是实现细节,在最近几个 V8 版本里已经变过两次。同一份坏掉的文档,在某个 Node 版本上报「Unexpected end of JSON input」,在另一个上报「Expected ‘,’ or ‘}’ after property value at position 6」,有时干脆不给位置。

所以解析失败时,本页会自己走一遍语法,报告它停下来的行、列和字符,并在下面标一个尖号。你拿到的报错信息,不取决于你碰巧在用哪个浏览器。

没人提醒你的那个精度问题

这个会造成真实的 bug,却几乎从没人提。JSON 的数字会变成 JavaScript 的数字,而 JavaScript 的数字是 IEEE 754 双精度浮点数。超过 2⁵³——大约 9.007 千万亿——的整数无法被精确表示。

推特、Discord 以及大多数 Snowflake 风格的 ID 方案所产生的那种 19 位标识符,取回来时会被悄悄改掉,任何地方都不会报错。把 {"id": 9007199254740993} 粘进上面的格式化器,看看最后一位是怎么变的。

修复要在产出端做:把 64 位标识符当作字符串发送。每一个被这件事咬过的 API,现在都这么做了。

什么时候该换别的工具

本页是用来读懂和修好一份摆在你面前的文档的。有两件相邻的活儿,它是错的工具:

  • 查询和变换。 那是命令行上的 jq,它还是流式的,不必把所有东西都装进内存——几兆字节以上的任何东西,正确答案都是它。
  • 约束结构。 那是 JSON Schema,而校验结构和校验语法是两个不同的问题。一份文档可以格式完全正确,同时缺掉你 API 要求的每一个字段。

相关

如果这份 JSON 是以 Base64 送来的,先解码它。如果它来自一个令牌,JWT 解码器会替你把两段都拆开并解析。而如果它要放进一个 URL,URL 编码器会告诉你该用三条转义规则里的哪一条。

JSON 相关问题

我的 JSON 看着没问题,为什么解析失败?

几乎所有情况都出自四个原因。收尾括号前多了一个逗号——JavaScript 接受,JSON 不接受。用了单引号而不是双引号。写了注释,而 JSON 根本没有注释的语法。以及没加引号的键名——{name: "x"} 是合法的 JavaScript,却是非法的 JSON。上面的校验器会告诉你它发现的是其中哪一种,而不是把解析器的报错原样复述一遍。

把生产数据粘进来安全吗?

粘进这个页面是安全的——它在你的浏览器里解析,没有任何请求能把它带走。你可以一边输入一边看网络面板来确认这一点。不过这个习惯值得一直保持:人们调试的 JSON 通常是一份真实的 API 响应,里面有真实的客户记录,而不少在线格式化工具会把它发到服务器上去处理。任何工具,粘贴之前先确认。

JSON 可以写注释吗?

不可以。Douglas Crockford 是故意去掉注释的,因为人们已经开始往注释里塞解析指令了。如果你的配置文件需要注释,通常的办法是用 JSON5 或 JSONC(VS Code 用的就是它),或者靠约定——加一个消费方会忽略的 "_comment" 键。这些都不是 JSON,所以严格的解析器照样会拒绝它们。

「键排序」是做什么的?我为什么要用它?

它会把每个对象的键按字母顺序递归重排。按规范,JSON 对象是无序的,所以两份仅仅键顺序不同的文档是等价的——但文本 diff 会把每一行都显示成改动过。比较之前把两边都排序,就能把它收敛成真正重要的那些差异。

有大小限制吗?

只有你浏览器的限制。解析发生在页面里,所以几兆字节在桌面上没问题,但会让一台老手机吃力。非常大的文档更适合在命令行上用 jq 处理,它是流式的,不必把整棵树都放进内存。

为什么我的大整数取回来就变了?

因为 JSON 里的数字会变成 JavaScript 的数字,也就是 IEEE 754 双精度浮点数,而它们在超过 2⁵³——约 9.007 千万亿——之后会丢失精度。一个 19 位的推特式 ID 或者数据库里的 bigint,取回来会被悄悄改动。这不是格式化工具的 bug;这正是使用 64 位 ID 的 API 会把它们当作字符串发送的原因。

最后审校于 。发现有内容过时了? 告诉我们.