JSON 格式化后字段少了:重复键覆盖怎样发现和处理
原文里明明有两组同名字段,格式化后却只剩一组,页面还提示成功。这种情况需要检查重复键。当前 JSON 工具会把同一对象中后出现的值保留下来;前面的值一旦被覆盖,不能再从格式化结果里找回来。
本篇用虚构配置演示覆盖发生在哪里,再看转义形式的键名为何也可能重复。操作前先保存原始文本,避免把便于阅读的结果覆盖唯一原件。
先看同一对象内的重复
打开“JSON格式化”,粘贴下面这段测试配置:
{"mode":"preview","mode":"live","nested":{"retry":1,"retry":3}}
顶层有两次 mode,嵌套的 nested 对象中有两次 retry。此时可以在编辑器里看到四组键值对,先记录这份原文,再点击“校验 / 格式化”。

本次输出为:
{
"mode": "live",
"nested": {
"retry": 3
}
}
两个位置都只保留后一次出现的值。页面的绿色提示说明本次格式化完成,没有提示“前一个值已被覆盖”,也没有给出重复键清单。

因此,不能把“校验 / 格式化”当成重复键检查器。原文中的 preview 和 1 没有被折叠在某一层,也不是编辑器滚动后还能看到;在这次输出中,它们已经不再属于对应字段的结果。
标准建议唯一,不代表所有解析器都报错
JSON 对象的成员名称应保持唯一。出现重复名称时,不同接收实现的行为可能不同:有的保留最后一项,有的报错,也有的能保留多项。当前工具这组输入表现为后值覆盖,不能把这一观察写成所有 JSON 系统一定遵循的规则。
这里的范围是“同一个对象”。两个不同对象里都使用 name,并不自动构成重复键。排查时要看字段完整路径,而不是在整份文本里搜索某个名字,发现两次就删除一次。
对于配置合并、接口拼接等场景,还应回到产生原文的位置检查。只把当前结果拿去继续处理,会掩盖上游本来同时提供了两个值的事实。
看起来不同的键名,也可能解析成同一个名字
再粘贴第二个样例:
{"name":"first","\u006eame":"last"}
第二个键的首字符写成 Unicode 转义 \u006e,解码后仍是字母 n,所以两个键都代表 name。点击“校验 / 格式化”后,本次只剩:
{
"name": "last"
}

这说明肉眼搜索完全相同的键名文本,可能漏掉转义后相同的名称。需要严格拦截重复键时,应在保留原始标记的解析阶段进行检查,而不是等普通对象已经生成、前值被覆盖后再数属性。
应当选一个值,还是保存多个值
如果业务上只允许一个模式或一个重试次数,应先确定哪一个才是有效配置,并在上游明确输出一个值。不要把“当前工具留下最后一个”当成业务上的优先级规则,更不要为了格式化成功就删除自己看不懂的那一项。
如果本来就需要保留多种模式或重试历史,可以与接收方约定数组。例如把演示数据改为:
{"modes":["preview","live"],"nested":{"retryHistory":[1,3]}}
本次格式化后,两个模式和两个历史值都保留在数组中。

这是一种新的数据结构约定,不是无条件修复。字段名、类型和接收逻辑都需要同步,不能在未知接口里直接替换。若只是为了排查覆盖,保留原始文本、记录对象路径和重复位置就足够,先不要改动业务数据。
得到格式化结果后,再对照原文检查关键字段的数量与值。发现少项时,从未加工原文重新定位,不要试图靠再次格式化恢复已经被覆盖的内容。