Bug, 教我停止差异化JSON作为文本花费了我大部分的周末。我运行的Laravel SaaS上的支付网络挂钩开始默默失败后, 提供商"非破坏"API更新 - 他们的话, 从更改日志。我从更新前的有效负载从我们的日志中拉出, 抓住一个新鲜的, 并把两者都扔进一个常规文本diff。每一行都亮了。提供者已经切换了他们的序列化器, 它按字母顺序重新排序每个键, 并将缩进从四个空格改为两个空格。六百个更改了行, 并在那里的某个地方, 一个真正的差异。我读了两次diff从上到下, 然后我找到了它: amount 已经从号码上改变了 1099 到字符串 "1099"屏幕上相同的字符 不同的类型 我们严格的比较拒绝了它,队列将其重新试用到地面上,文本diff已经将一个有意义的变化埋在599个化妆品下。
That's的根本问题:JSON是一种数据格式,但文本差异将其视为散文。键序,空白,缩进,尾随换行符-对JSON解析器来说,它没有任何意义,并且所有内容都显示为基于行的比较中的变化。Per RFC 8259中,JSON 对象是一个 无序 name/value pairs的集合,两个文档可以字节对字节不同,语义相同,一个逐行比较JSON的工具就是答错问题。
甲 JSON diff 工具 回答正确。它将两个文档解析为树并进行比较 值:添加了这个键,删除了那个键,这个值从 X 变为 Y,并且 - 保存了我的周末的那个,如果当时它存在于我的浏览器选项卡中 - 这个值发生了变化 类型。当我为toolz。dev构建差异检查器时,类型-变化检测是列表中的第一个功能,因为它's 改变类,文本差异在结构上无法浮出水面,并且最常破坏真实系统。
本指南涵盖了结构比较如何工作、数组顺序何时应该和应该't 事项,以及调试工作流程 - API 回归、配置漂移、包显式审核 - 其中 JSON diff 每周为自己付费。
TL;博士: 将两个 JSON 文档粘贴到 Toolz.dev JSON 差异检查器 并进行结构比较:添加、删除和更改具有精确路径的键,例如
features.rateLimit或users[3].email- 加上值更改时的单独标记 类型 (thexp),在2019年10月10日开始实施,在2019年10月11日开始实施,在2019年10月11日开始实施,在2019年10月11日开始实施3000→"3000"bug)。按键顺序和格式化永远不会产生误报。一切都在你的浏览器中运行;什么都没有上传。与。 json格式化程序 首先清理文档 文本差异工具 为线条实际重要的内容。
从结构上改变 JSON 意味着什么?
A structure diff 将两个文档解析成它们的实际数据树,并把它们一起走,一个键一个键,一个元素一个元素 在每个节点它都会问:这个键是否存在于两边?值是否是同一类型?它们是否相等?输出是't "line 14 改变"- it's 关于你的数据的事实列表:
version改变自"1.4.0"到"1.5.0"features.metrics被增值了trueport将类型从数字更改为字符串tags[2]被增值了"monitored"
每个差异都承载其完整的 JSON 路径,因此在深度嵌套的文档中,您确切地知道在哪里查看。 users[12].address.postalCode 告诉您哪个用户、哪个字段不需要滚动。
与文本差异的对比在现实世界文档中最为鲜明。拿一个 package.json npm版本不同、后台团队升级序列化器后的api响应或通过格式化程序运行的config文件而重新生成文本diff:数百行更改结构diff:实际发生的三个更改,或者诚实的答案是没有- "结构上相同的"- 这本身就很有价值,证实产生了一个风险重构 零 数据更改是我使用此工具的一半原因。
There's一个行差异的地方,要清楚散文,代码,HTML,任何物理布局带有意义的地方 - 那's 文本差异 tritory。but JSON's布局没有携带任何意义, 规格, 和一个比较假装不然是产生噪音然后你必须用眼睛过滤。
为什么类型更改值得自己的类别?
因为它们'在数据的每一个其他视图中都是不可见的,而且它们以调试起来很糟糕的方式破坏东西。
1099 並 "1099" 在日志文件、终端和大多数文本差异中呈现相同 - 上午 2 点时很容易错过报价。但对于任何类型的消费者来说,它们都是不同的值。 JavaScript's === 拒绝比较。 JSON 模式声明 "type": "integer" 验证失败。 Go 服务解编为 a int64 java 中返回错误;一个严格的 Jackson 反序列化器抛出。PHP 以宽松的比较着名地宽恕,但当你启用严格类型的那一刻 - 每个现代 Laravel 代码库都应该 - "1099" 停止做钱并开始成为例外。
最肮脏的部分是 哪里 这些变化来自。几乎从来不是来自开发人员故意编辑值。它们来自序列化器交换、ORM 升级、数据库列迁移 INT 到 VARCHAR、字符串化数字的缓存层,或者善意的 API 网关 "标准化 " 有效负载。没有人为他们编写更改日志条目,因为没有人知道他们发生了。
所以 json 差异检查器 report 类型更改作为自己的类别 - ! 在可复制的报告中,有别于普通的价值变化- 拼出新旧类型当你're盯着一个总结说 0 added, 0 removed, 0 changed, 1 type changed,你确切知道你're猎杀在你之前've读到一条单一的路径。
如何将两个 JSON 文件与该工具进行比较?
1步:粘贴两个文档
原(或已知-好)JSON进入左侧面板,更新(或怀疑)JSON在右侧。约定仅对读取输出很重要:"添加"表示出现在右侧而不是左侧,"删除"表示相反。如果您'重新将工作环境与损坏的环境进行比较,将工作放在左侧,差异读取为"什么损坏改变了。"
There's 一个加载样本按钮,用一个小的服务配置填充两个面板,锻炼每个差异类型 - 值变化,添加,类型变化,数组增长 - 这是学习输出如何读取的最快方法。
2步:决定数组顺序是否重要
这是您需要考虑的一个选项,正确的答案取决于您的数组 意味着- 更多关于下面的内容。默认是顺序敏感的,它与 JSON 规范相匹配。当您的数组是语义集时,勾选 "忽略数组顺序 "。
3步:比较一下
2个文档在比较任何东西之前都经过验证。如果任何一方都有一个语法错误-尾部逗号,单引号,一个未引号的密钥,通常的嫌疑人-你得到解析器's精确消息,最重要的是, 哪一边 它来自。没有无声的失败,没有比较的半截面的垃圾。如果你'不确定你的JSON是否有效,运行它通过 json格式化程序 首先;它一步验证并漂亮打印。
步骤 4:阅读摘要,然后阅读表格
总结行按类别为您提供计数 - 添加、删除、更改、类型更改 - 这通常是您所需要的。 "47 已添加、0 已删除、0 已更改" API 版本后,bump 仅表示新字段:安全。 "0 已添加、3 已删除"意味着您的消费者可能依赖的字段刚刚消失:不安全。下表列出了每个差异及其路径、旧值和新值,并截断以获得长值的可读性。
第 5 步:复制报告
复制报告按钮生成纯文本摘要 + / - / ~ / ! markers和完整路径 - 设计为直接粘贴到拉请求评论,Slack事件线程或票证。 "这里's恰好在分期和生产配置之间发生了什么变化"与收据,一键。
您什么时候应该忽略数组顺序?
JSON 数组按规范排序 - [1, 2] 並 [2, 1] 是不同的文档,默认的比较尊重这一点。但规范描述了容器,而不是你的意图,并且在实践中,数组被使用两种不同的方式:
数组作为序列,其中位置是含义:按顺序执行的中间件链、迁移列表、排序的排行榜、分页的结果,重新排序这些都是一个真正的改变- 一个运行的中间件堆栈 auth 之后 handle 是(很可能已经坏了)的应用。保持订单敏感性。
数组作为集合、位置为意外:标签列表、角色分配、特征标志、数据库查询返回的 ID,其中没有 ORDER BY。Postgres完全在其权利范围内,可以在不同的运行中以不同的顺序返回相同的行,如果您的差异因此而亮起,则's噪声。这就是"忽略数组顺序"选项对于-元素进行匹配,无论位置如何,所以 ["admin", "editor"] 等于 ["editor", "admin"]。
API有效负载多年比较的经验法则:如果后端应用显式排序,则将数组视为序列;如果没有't,它's一个集合,无论作者是否意识到,顺序不敏感的比较告诉你数据的真相。
结构差异与文本差异与手动检查
| 结构 JSON 差异 | 文本/行差异 | 眼球棒它 | |
|---|---|---|---|
| 重新排序的键 | 没有报告差异 | 每移动一行都被标记 | 易于错过更改 |
| 重新格式化的空格 | 没有报告差异 | 一切都被标记了 | 不适用 |
类型更改 (1 → "1") |
标记为类型更改 | 线条海洋中的两个角色 | 几乎看不见 |
| 嵌套更改位置 | 确切的路径: a.b[2].c |
行号在 格式化 文本 | 手动遍历 |
| 数组重新排序(有意) | 旗(或忽略,您的选择) | 标记 | 取决于数组大小 |
| 最好的 | JSON、API 有效负载、配置 | 代码、散文、标记 | 两行文档 |
| 故障模式 | 有效 JSON 上没有 | 误报掩盖了真正的变化 | 人类的疲劳 |
诚实的总结:文本差异是'错了,他们'重新回答了一个不同的问题 - "字节变了吗?"对于 JSON,您几乎总是想要"有 数据 改?",而那些问题却出奇地经常有不同的答案。
JSON 差异的真实世界工作流程是什么?
调试 API 回归
Webhook故事中的工作流程,现在已经系统化:从更改之前捕获一个有效负载(日志,一个录制的夹具,你的测试套件's快照)和一个从之后。左面板,右面板,比较。diff在几秒钟内告诉你提供商's更改日志没有't - 哪些字段移动,哪些更改了类型,哪些悄然消失。每次第三方API宣布版本颠簸时,我都会这样做, 之前 旧版本日落,并在升级票中提交报告。
捕获配置漂移
舞台作品、制作 does't,两者都是从同一配置部署的。 "它们是吗?两者都导出 - 环境 JSON,a docker inspect 输出,转储的 Kubernetes ConfigMap -o json-并差异他们。Config漂移几乎总是一两个键,路径列带你直奔那里。这节拍 diff <(jq -S . a.json) <(jq -S . b.json) 在终端中,因为它还捕获类型更改,其中 jq-标准化文本差异几乎是无形的。
审查锁定文件和清单更改
甲 package.json 或 composer.json that 被冲突的合并所破坏,或者在框架升级后生成的 OpenAPI 规范:结构差异向您显示依赖关系变化,而没有再生格式化的噪声对于 WordPress 插件工作 - WP 管理将设置设为 JSON - 我在发布之间差异导出的设置模式以确保重构没有't 丢弃数千次安装所依赖的密钥意外删除显示为 a - 行;在 4,000 行设置导出的文本差异中,它显示为完全没有。
验证数据迁移
Before:导出一个代表性记录为JSON 迁移之后:再次导出,diff应该准确显示迁移所要和的变化 没有别的。"结构上相同"在应该't被触及的记录上,这是你'll运行过的最便宜的回归测试。这与转换表格导出很好地配对通过 CSV 转 JSON 当数据以 CSV 形式从数据库中出来时。
比较环境响应
2个环境中击中相同的端点,差异响应。dev中存在但生产中缺失的字段通常意味着特征标志,陈旧的部署或从未设置的环境变量。仅摘要就计算通常会对其进行诊断。
为什么该工具的客户端处理比大多数工具更重要?
想想你粘贴到 JSON diff 中的内容:带有客户电子邮件的 API 响应、带有内部主机的配置文件、带有支付元数据的 Webhook 有效负载、数据库导出。这正是不得泄漏的数据,恰好粘贴在事件发生中期的那一刻 - 当没有人审计时哪个在线工具刚刚收到它。
的 Toolz.dev 差异检查器 完全在浏览器中进行解析和比较。任何请求都不会将文档带到任何地方;一旦页面加载,该工具就会离线工作,您可以通过切断网络并再次进行比较来验证。这是't高级功能或可能改变的政策承诺 - it's架构。比较逻辑是纯JavaScript在内存中操作的两个解析树。没有服务器组件可以发送数据。
同样的隐私论点也适用于整个工具箱 - it's 的原因 toolz。dev 上的开发人员工具包 是浏览器优先构建的 - 但差异工具是它's最尖锐的地方,因为比较 两 制作文档使粘贴文档的曝光度增加了一倍。
您可以比较多大的文档?
比较访问两棵树中的每个节点一次,因此工作会随着文档大小线性缩放。在实践中:数百千字节中的文档立即进行比较;在任何类似于现代笔记本电脑的东西上,低个位数兆字节的完成时间远低于一秒;数十兆字节的工作但您'会感觉到,因为浏览器必须同时解析两个文档并将两个树放在内存中。
2个非常大的有效载荷的实用技巧,首先,如果你只关心文档的一部分,就比较一下那个子树- 粘贴 response.data.items 从两边而不是整个信封。其次,如果diff产生数千个条目,那么's通常一个符号的一边是不同的 形状 (一个包裹在对象中的数组,一个额外的嵌套级别)- 在滚动之前检查前几条路径;它们'll告诉你你're看一个结构变化级联还是成千上万的真正。
常问问题
如何在线比较两个JSON文件?
打开 json 差异检查器、将一个文档粘贴到左侧面板,将另一个粘贴到右侧,然后单击比较。您将获得每个添加、删除、更改和类型更改值的分类列表及其确切的 JSON 路径。这两个文档完全在您的浏览器中处理 - 没有任何内容上传到任何服务器。
为什么当我的 JSON 数据相同时,文本差异会显示如此多的变化?
因为文本差异比较行,而 JSON 允许以多种方式编写相同的数据。重新排序的键、不同的缩进和空白都可以在不更改数据的情况下更改文本。结构差异首先解析文档并比较实际值,因此格式差异会产生零报告更改。
JSON对象中的键的顺序重要吗?
No。RFC 8259 将 JSON 对象定义为名称/值对的无序集合,因此 {"a":1,"b":2} 並 {"b":2,"a":1} 是同一个对象,diff 检查器按键名比较对象,从不将重新排序报告为更改,相比之下,数组元素顺序默认是显着的 - 数组在规范中排序。
我应该何时使用 "忽略数组顺序"选项?
当您的数组是语义集合而不是序列时使用它 - 标签列表、角色集合、来自未排序数据库查询的 ID。 打开选项, [1,2,3] 並 [3,1,2] compare as equal。position 带有意义时,如有序的中间件链、排名结果或分页列表,请将其保留。
什么是类型更改以及为什么单独标记?
类型更改是指当值's JSON 类型在文档之间即使看起来相似 - 编号也不同时 3000 成为字符串 "3000" 是经典案例。it's单独标记,因为它打破了严格类型的消费者,模式验证和严格的平等检查,同时在文本差异和日志中几乎看不见。it's是api集成回归的最常见原因之一。
我可以与我的团队分享比较结果吗?
是复制报告按钮生成一个纯文本差异报告 + (已添加), - (已删除), ~ (已更改),以及 ! (类型已更改)标记和每个差异的完整 JSON 路径。It's 格式化为干净地粘贴到拉请求注释、Slack 线程和问题跟踪器中。
将生产 API 响应粘贴到工具中安全吗?
是的。解析和比较完全在浏览器中的 JavaScript 中运行 - 不会对您的数据提出网络请求,不会记录或存储任何内容,并且该工具会保持离线工作。这使得包含客户数据、内部主机名或凭据的有效负载变得安全,尽管在共享之前会编辑秘密 报告 仍在你身上。
如果我的一份文件是't有效的JSON会发生什么?
该工具在比较之前验证两侧,并报告解析器's精确的错误消息以及它来自哪一侧 - 左或右 常见的罪魁祸首是尾随逗号、单引号而不是双引号、未引号的键。修复报告的问题,或通过运行文档 json格式化程序 要找到问题,请再次比较。
结构比较是改变哪些错误的工具之一 看见。文本差异答案"字节是否更改?";对于 JSON,重要的问题是"数据是否更改?" - 对于运行系统的 API 有效负载、配置和清单, json 差异检查器 在您的浏览器中,在您的数据永远不会离开您的机器的情况下,在几秒钟内回答它。更多 JSON 工作流程 - 格式化、验证、转换 - 实时 编码工具指南。



