Appendix A. Frequently Asked Questions (常见问题)
A.1 Why Not JSON? (为什么不用JSON?)
早期的结构化字段提案基于JSON [RFC8259]。然而,约束其使用以使其适合HTTP头部字段需要发送者和接收者实现特定的额外处理。
问题1: 规范问题
JSON在大数字和具有重复成员的对象方面存在规范问题。
// 问题: 大数字
{"value": 9007199254740993} // 超过JavaScript安全整数范围
// 问题: 重复键
{"key": "value1", "key": "value2"} // 行为未定义
虽然有避免这些问题的建议(例如,[RFC7493]),但无法可靠依赖。
问题2: Unicode字符串
JSON字符串默认是Unicode字符串,这有许多潜在的互操作性问题(例如,在比较中)。
// 不同的Unicode表示可能导致问题
"café" // é as single character
"café" // é as e + combining accent
// 这两个看起来相同但二进制不同
虽然可以建议实现者在不必要的地方避免非ASCII内容,但这很难强制执行。
问题3: 任意嵌套深度
JSON能够将内容嵌套到任意深度。
{
"a": {
"b": {
"c": {
"d": {
// ... 无限深度
}
}
}
}
}
后果:
- 内存承诺可能不合适(例如,在嵌入式和其他有限的服务器部署中)
- 需要以某种方式限制它
- 现有的JSON实现没有这样的限制
- 即使指定了限制,某些字段定义也可能需要违反它
问题4: 实现诱惑
因为JSON被广泛采用和实现,很难在所有实现中强加额外的约束;某些部署将无法强制执行它们,从而损害互操作性。
简而言之: 如果它看起来像JSON,人们会倾向于在字段值上使用JSON解析器/序列化器。
结论
由于结构化字段的主要目标是改进互操作性和简化实现,这些担忧导致采用了需要专用解析器和序列化器的格式。
此外,有广泛共识认为JSON在HTTP字段中"看起来不对"。
对比总结
| 特性 | JSON | RFC 8941 |
|---|---|---|
| 数字范围 | 不确定(依赖实现) | 明确定义(15位整数) |
| 小数精度 | 不确定 | 3位小数 |
| Unicode | 默认支持 | 仅ASCII(可用Byte Sequence) |
| 嵌套深度 | 无限制 | 限制为2层 |
| 重复键 | 未定义 | 明确禁止 |
| 类型系统 | 宽松 | 严格 |
| 解析器复杂度 | 高(需要额外约束) | 中(专用但简单) |
| HTTP适配 | 差 | 优秀 |
实际示例
JSON方式(问题)
Example-Header: {"priority": 1, "timeout": 3.14159, "enabled": true}
问题:
- 需要JSON解析器
- 小数精度不确定
- 如果使用Unicode会有问题
- 在HTTP头部中显得冗长
结构化字段方式(解决方案)
Example-Dict: priority=1, timeout=3.142, enabled
优点:
- 简洁明了
- 精度明确(3位小数)
- 仅ASCII
- 看起来"属于"HTTP头部
其他被考虑的格式
1. XML
- 太冗长
- 解析复杂
- 不适合简单的键值对
2. Protocol Buffers
- 需要schema
- 二进制格式(不适合HTTP/1.1文本头部)
- 过于复杂
3. MessagePack
- 二进制格式
- 不适合HTTP/1.1
- Base64编码会抵消大小优势
关键要点
- JSON不够严格: 对于HTTP头部需要太多额外约束
- 互操作性优先: 专用格式确保一致性
- 实现现实: 人们会使用通用JSON解析器,破坏严格性
- 外观重要: 字段值应该"看起来"属于HTTP
- 未来友好: 设计允许二进制编码(HTTP/2、HTTP/3)
引用
"If it looks like JSON, people will be tempted to use a JSON parser/serializer on field values."
—— RFC 8941
这总结了为什么需要不同格式的核心原因。