guide/json-diff.md

如何对比 JSON — 键排序与规范化

介绍对比两段 JSON 时,如何消除因键顺序、缩进、数字写法不同而产生的假差异,并说明数组顺序、大整数以及与 JSON Patch 的区别。

最后更新: 2026-09-23

API 响应、配置文件、翻译文件等 JSON 格式的数据,经常需要比较。可是如果直接对两段 JSON 做文本比较,常常会出现数据明明相同却报出一大堆差异的情况。本文说明其原因和解决方法。

为什么会出现假差异

JSON 标准(RFC 8259)把对象定义为“无序的名称/值对集合”。也就是说,{"a":1,"b":2}{"b":2,"a":1} 表示的是同一份数据。但作为文本,两者的行顺序不同,diff 就会把它当作差异。此外,下列差异也与数据本身无关:

解决办法:先解析,再按同样的格式重新输出

最可靠的方法是把两段 JSON 解析成数据,再按同样的规则重新序列化

  1. 把两段文本解析为 JSON。如有语法错误,先修正。
  2. 递归地对所有对象的键进行排序。
  3. 用相同的缩进(如 2 个空格)重新输出。
  4. 按行比较输出结果。

例如,下面两段 JSON 的键顺序和数组顺序都不同。

{"name":"kim","age":30,"tags":["a","b"]}
{"age":30,"name":"kim","tags":["b","a"]}

排序并重新输出后,键顺序的差异消失了,只剩下真正的差异——数组顺序。

@@ -2,7 +2,7 @@   "age": 30,   "name": "kim",   "tags": [-    "a",-    "b"+    "b",+    "a"   ] }

不要对数组排序

与对象不同,数组的顺序是有意义的。 ["a","b"]["b","a"] 是不同的数据。因此,规范化时原则上不对数组排序。不过,如果是标签列表这类在业务上顺序并不重要的数组,比较前自行排序会让结果更易读。哪种做法正确,取决于数据的含义。

解析会改变的东西

先解析再重新输出的方法有一些值得注意的副作用:

在命令行中操作

如果安装了 jq,可以用 -S--sort-keys)选项输出按键排序后的结果。

jq -S . before.json > a.json
jq -S . after.json  > b.json
diff -u a.json b.json

与 JSON Patch 的区别

diff 的结果是供人阅读的、按行列出的变更清单。而 JSON Patch(RFC 6902)是用 JSON 结构中的路径来表示变更的标准,例如 {"op":"replace","path":"/age","value":31};JSON Merge Patch(RFC 7396)则是把只含变更部分的 JSON 覆盖到原数据上的方式。程序之间交换变更时适合用这些标准,人工审查时则适合用排序后的文本 diff。

在本工具中试一试

文本对比工具 的选项中开启 JSON 键排序,就会先解析两侧内容、对键排序、以 2 个空格缩进重新输出,然后再比较。数组顺序保持不变;解析失败时,会提示是哪一侧、第几个字符出错。也可以一次拖入两个 .json 文件。把结果当作 patch 阅读的方法,请参阅 unified diff 阅读指南

前往文本对比工具