跳到主要内容
数据处理2026-05-295 分钟阅读

在线 JSON Diff 工具:比较和分析 JSON 数据差异

什么是 JSON Diff

JSON Diff 是比较两个 JSON 数据结构并找出差异的过程。它能识别出两个 JSON 对象之间的新增、删除和修改。把两段数据贴进我们的 JSON Diff 工具,即可并排高亮显示所有差异。

比较示例

原始 JSON:

{
  "name": "张三",
  "age": 28,
  "hobbies": ["reading", "gaming"]
}

修改后的 JSON:

{
  "name": "张三",
  "age": 29,
  "hobbies": ["reading", "coding"],
  "email": "zhang@example.com"
}

Diff 结果:

{
  "age": { "old": 28, "new": 29 },
  "hobbies[1]": { "old": "gaming", "new": "coding" },
  "email": { "added": "zhang@example.com" }
}

为什么需要 JSON Diff

  1. API 响应验证:比较 API 返回值与预期值(在线 JSON Diff 工具支持四档对比粒度,粘贴即比)
  2. 配置变更检测:对比配置文件的修改
  3. 数据迁移验证:确认数据迁移的正确性
  4. 代码审查:比较两个版本的 JSON 输出
  5. 自动化测试:在测试中断言数据变化
  6. 版本控制:追踪 JSON 数据的变更历史

Diff 结果类型

变更类型说明标识
新增键不存在于原始 JSON+ 或 added
删除键存在于原始但不在修改后- 或 deleted
修改键存在但值不同~ 或 changed
未变键和值都相同无标记

如何使用在线工具

使用 ToolVault 工具匣 的 JSON Diff 工具:

  1. 在左侧输入原始 JSON
  2. 在右侧输入修改后的 JSON
  3. 工具自动比较并高亮显示差异
  4. 显示新增、删除、修改的具体内容
  5. 支持复制 Diff 结果,或一键复制 RFC 6902 JSON Patch

降噪对比:忽略数组顺序与忽略字段

对比 API 响应或日志时,真正想看的字段常被两类噪音淹没:顺序无关的数组(标签、权限列表)和每次必变的元字段(updatedAt、traceId)。工具面板提供三个选项:

  • 忽略数组顺序:数组按内容多集匹配——[1,2,3] 和 [3,1,2] 无差异;剩余元素按「最小差异」两两配对,报成修改而不是「整行删除+整行新增」。
  • 数组对齐键(如 id):配合忽略顺序使用,对象数组按业务键对齐,同 id 的行即使位置变了、其他字段改了,也能精确报出 users[id=7].name 级别的字段差异。
  • 忽略字段:逗号分隔的字段名(任意层级生效),如 updatedAt, traceId——比对时直接跳过,让差异清单只剩信号。

判断标准不变:对顺序敏感的接口(时间线、榜单)不要开「忽略数组顺序」;不确定时先用默认按位置模式跑一遍。

导出 JSON Patch(RFC 6902)

差异清单是给人读的;给机器(CI 断言、变更回放)用的是 JSON Patch。点击「复制 JSON Patch」得到标准 add / remove / replace 操作序列,路径为 JSON Pointer(如 /config/timeout)。两个边界要知道:

  • 开启「忽略数组顺序」时,数组路径是逻辑位置而非下标,无法映射成可执行 patch——该模式下不显示 patch 按钮,请改用 diff 清单。
  • patch 文本内的大整数(如雪花 ID)按原文输出不丢精度;但任何经 JSON.parse 消费 patch 的实现,数字仍受 IEEE 754 双精度限制——这是 patch 协议本身的边界,不是工具实现问题。

代码中的 JSON Diff

JavaScript

// 深度比较两个对象
function deepDiff(oldObj, newObj, path = '') {
  const diffs = {};
  const allKeys = new Set([...Object.keys(oldObj), ...Object.keys(newObj)]);

  for (const key of allKeys) {
    const currentPath = path ? `${path}.${key}` : key;

    if (!(key in oldObj)) {
      diffs[currentPath] = { type: 'added', value: newObj[key] };
    } else if (!(key in newObj)) {
      diffs[currentPath] = { type: 'deleted', value: oldObj[key] };
    } else if (typeof oldObj[key] === 'object' && typeof newObj[key] === 'object') {
      Object.assign(diffs, deepDiff(oldObj[key], newObj[key], currentPath));
    } else if (oldObj[key] !== newObj[key]) {
      diffs[currentPath] = { type: 'changed', old: oldObj[key], new: newObj[key] };
    }
  }

  return diffs;
}

Python

def deep_diff(old, new, path=''):
    diffs = {}
    all_keys = set(list(old.keys()) + list(new.keys()))

    for key in all_keys:
        current_path = f"{path}.{key}" if path else key

        if key not in old:
            diffs[current_path] = {'type': 'added', 'value': new[key]}
        elif key not in new:
            diffs[current_path] = {'type': 'deleted', 'value': old[key]}
        elif isinstance(old[key], dict) and isinstance(new[key], dict):
            diffs.update(deep_diff(old[key], new[key], current_path))
        elif old[key] != new[key]:
            diffs[current_path] = {'type': 'changed', 'old': old[key], 'new': new[key]}

    return diffs

行 diff 对 JSON 说谎的两种方式

一行的 minified JSON 没有行可 diff——行 diff 报告「全变了」;美化打印后的键重排(同一对象、字母序不同的序列化器)产生千行文本 diff 而语义零变化。修复是结构化:解析两侧、比较树、报告路径——对象键序不敏感(JSON 规范如此)、数组序敏感(语义如此)。我们的 JSON diff 做的就是结构化比较;它编码的纪律是:机器生成的 JSON 用行 diff 是选错了工具,行 diff 留给手编文件(行上下文有含义的场合)。

数组 diff 的对齐问题

朴素工具按位置 diff 数组:删了第 5 个元素,后面全部位移——一次插入报成 N 处变更。聪明的数组 diff(LCS 最长公共子序列,与文本 diff 同源)按内容对齐、报出那一次插入。代价:大对象数组的 LCS 昂贵,且「相似但不相等」的元素(同 id 不同字段)让朴素对齐失效——生产级答案是按 id 字段键对齐(把数组当 map diff)。你的 diff 工具在小改动上报出大面积数组变更,就是缺键对齐;用一个带 id 的样本一测便知。

规范化先行:稳定比较的礼仪

机器写的 JSON 因序列化器而异:键序、数字格式(1.0 与 1)、unicode 转义(\u0041 与 A)、无意义空白。规范化——先做规范序列化(键排序、数字标准化)再 diff——把这一整类噪音消除。RFC 8785(JSON 规范化方案)是正式规范;务实子集(排序键+规范数字)拿走 95% 的收益。先规范化的 diff 报信号;diff 裸字节的报序列化器癖好。diff 进自动化管线(发布说明、变更检测)时规范化不是可选项——否则每次序列化器升级都误报。

FAQ

JSON Diff 能处理大文件吗?

工具在浏览器本地做全量递归对比:几 MB 级的配置/响应对比是秒级;超过 10MB 的超大文件建议先用「忽略字段」裁掉无关子树,或先在本地用 jq 抽取关心的路径再对比。「忽略数组顺序」的剩余元素配对是 O(n²) 贪心策略,上千元素的乱序数组会明显变慢——元素有业务键时填上「数组对齐键」可大幅降低配对成本。

Diff 结果可以合并吗?

可以。点击「复制 JSON Patch」得到 RFC 6902 标准 patch(add / remove / replace),可被 fast-json-patch 等库直接 apply 回原始 JSON。注意「忽略数组顺序」模式下路径无下标语义,patch 不可用。

数组顺序变化怎么处理?

数组 Diff 有两种策略:按位置比较(默认,严格但受顺序影响)和按内容比较(勾选「忽略数组顺序」,顺序无关但牺牲位置信息)。元素是带 id 的对象时,再填「数组对齐键」按业务键对齐,可同时获得「顺序无关」和「字段级精确差异」。

实现注记

做这个工具时踩过一个大整数坑:解析必须走无损模式(保留数字原文),比较时同值大整数按 raw 原文判等——如果按解析产物的实例引用比较,两个数值相同的大整数 ID 也会被报成 modified,纯属假差异。


ToolVault 工具匣 出品的开发者指南。其他在线工具可在 首页 找到。