JSON 标准指南:RFC 6901, 6902 和 7396
JSON 已成为 Web 数据交换的事实标准。然而,随着 API 变得越来越复杂,简单的 JSON 对象往往不够用。开发者需要标准化的方法来引用 JSON 文档的具体部分,并描述对这些文档的更改。这就是 RFC 6901 (JSON Pointer)、RFC 6902 (JSON Patch) 和 RFC 7396 (JSON Merge Patch) 的用武之地。
什么是 JSON Pointer 和 Patch?
- RFC 6901 (JSON Pointer):定义了一种字符串语法,用于标识 JSON 文档中的特定值。它就像数据的“地址”。
- RFC 6902 (JSON Patch):定义了一种 JSON 文档结构,用于表达要应用于 JSON 文档的一系列操作。它就像“差异”或“事务日志”。
- RFC 7396 (JSON Merge Patch):提供了一种描述更改的更简单方法,即发送一个看起来像目标文档但仅包含更改字段的“补丁”文档。
1. RFC 6901: JSON Pointer
JSON Pointer 使用正斜杠 (/) 分隔的语法来导航 JSON 对象的层次结构。
语法规则:
/表示根。/foo指向 "foo" 键的值。/foo/0指向 "foo" 数组的第一个元素。~1用于表示字面量/。~0用于表示字面量~。
示例:
{
"biscuits": [
{ "name": "Digestive" },
{ "name": "Choco" }
]
}
Pointer /biscuits/1/name 将解析为 "Choco"。
2. RFC 6902: JSON Patch
JSON Patch 是一个操作对象数组。每个对象必须有一个 op 字段。
操作:
- add:在指定路径添加值。
- remove:移除路径处的值。
- replace:替换路径处的值。
- move:将值从一个路径移动到另一个路径。
- copy:将值从一个路径复制到另一个路径。
- test:测试路径处的值是否符合预期。
补丁示例:
[
{ "op": "replace", "path": "/biscuits/0/name", "value": "Oatmeal" },
{ "op": "add", "path": "/biscuits/-", "value": { "name": "Ginger" } }
]
/biscuits/- 中的 - 表示“数组末尾”。
3. RFC 7396: JSON Merge Patch
JSON Merge Patch 比 RFC 6902 简单得多。您只需发送一个 JSON 对象,该对象表示您要更改的字段的最终状态。
规则:
- 如果补丁包含具有非空值的字段,则更新或添加该字段。
- 如果补丁包含具有
null值的字段,则从目标中移除该字段。 - 它不适合修补数组(它会替换整个数组)。
示例:
目标:
{ "a": "b", "c": "d" }
补丁:
{ "a": "z", "c": null, "e": "f" }
结果:
{ "a": "z", "e": "f" }
}
比较:Patch vs. Merge Patch
| 特性 | RFC 6902 (Patch) | RFC 7396 (Merge Patch) |
|---|---|---|
| 复杂度 | 高(操作数组) | 低(基于对象) |
| 效率 | 极高(手术级修改) | 中等(字段级) |
| 数组支持 | 完全支持 | 较差(替换整个数组) |
| 原子操作 | 是(test 操作) | 否 |
| 适用场景 | 复杂状态更改 | 简单属性更新 |
常见问题 FAQ
问:我的 API 应该使用哪一个? 答:对于不需要精确数组操作的简单资源更新,请使用 JSON Merge Patch (7396)。对于复杂资源、高性能要求或需要原子“测试并设置”操作的情况,请使用 JSON Patch (6902)。
问:我可以在 URL 中使用 JSON Pointer 吗?
答:可以,在 URI 片段中使用 JSON Pointer 很常见(例如 example.com/schema.json#/definitions/user)。
问:如何处理键中的特殊字符?
答:使用 ~1 表示 /,使用 ~0 表示 ~。例如,名为 a/b 的键引用为 /a~1b。
相关工具
- JSON 格式化与校验 - 使用此工具校验您的 Patch 或 Merge Patch 文档。
- JSON 转 CSV 转换器 - 将您的 JSON 数据展平以进行分析。