跳到主要内容

4. 在 CBOR 和 JSON 之间转换数据

本节给出关于在 CBOR 和 JSON 之间转换的非规范性建议. 转换器的实现可以自由采用这里它们想要的任何建议.

值得注意的是, JSON 文本是字符序列, 而不是编码的字节序列, 而 CBOR 数据项由字节而非字符组成.

4.1. 从 CBOR 转换为 JSON​

CBOR 中的大多数类型在 JSON 中都有直接对应. 然而有些没有, 实现 CBOR 到 JSON 转换器的人必须考虑在这些情况下该怎么做. 以下非规范性建议通过将它们转换为单个替代值 (例如 JSON null) 来处理这些情况.

  • 整数 (主类型 0 或 1) 变为 JSON 数字.

  • 未嵌入到规定某种建议编码的标签中的字节串 (主类型 2), 以不带填充的 base64url 编码, 并变为 JSON 字符串.

  • UTF-8 字符串 (主类型 3) 变为 JSON 字符串. 注意, JSON 要求对某些字符进行转义 (RFC 4627 第 2.5 节): 引号 (U+0022)、反斜杠 (U+005C) 以及 "C0 控制字符" (U+0000 到 U+001F). 所有其他字符都原样复制到 JSON UTF-8 字符串中.

  • 数组 (主类型 4) 变为 JSON 数组.

  • 映射 (主类型 5) 变为 JSON 对象. 只有在所有键都是 UTF-8 字符串时才能直接做到这一点. 转换器也可以把其他键转换为 UTF-8 字符串 (例如将整数转换为包含其十进制表示的字符串); 然而, 这样做会带来键冲突的风险.

  • False (主类型 7, 附加信息 20) 变为 JSON 的 false.

  • True (主类型 7, 附加信息 21) 变为 JSON 的 true.

  • Null (主类型 7, 附加信息 22) 变为 JSON 的 null.

  • 浮点值 (主类型 7, 附加信息 25 到 27) 如果是有限的 (也就是说, 它可以用 JSON 数字表示), 则变为 JSON 数字; 如果该值是非有限的 (NaN, 或正负 Infinity), 则由替代值表示.

  • 任何其他简单值 (主类型 7, 尚未讨论的任何附加信息值) 都由替代值表示.

  • 大数 (主类型 6, 标签值 2 或 3) 通过将其字节串以不带填充的 base64url 编码来表示, 并变为 JSON 字符串. 对于标签值 3 (负大数), 在 base 编码值之前插入一个 "~" (ASCII 波浪号). (转换为二进制数据块而不是数字, 是为了防止 JSON 解码器可能出现的数值溢出.)

  • 带有编码提示的字节串 (主类型 6, 标签值 21 到 23) 按所述方式编码, 并变为 JSON 字符串.

  • 对于所有其他标签 (主类型 6, 任何其他标签值), 内嵌的 CBOR 项表示为 JSON 值; 标签值被忽略.

  • 不定长项在转换之前先转为定长.

4.2. 从 JSON 转换为 CBOR​

所有 JSON 值一经解码, 就直接映射为一个或多个 CBOR 值. 与任何形式的 CBOR 生成一样, 必须就数字表示作出决定. 在一种建议的转换中:

  • 没有小数部分的 JSON 数字 (整数) 表示为整数 (主类型 0 和 1, 也可能是主类型 6 标签值 2 和 3), 并选择最短形式; 长于实现定义阈值 (通常为 32 位或 64 位) 的整数可以改为表示为浮点值. (如果该 JSON 是由 JavaScript 实现生成的, 其精度已经最多限制为 53 位.)

  • 带有小数部分的数字表示为浮点值. 最好使用最短的精确浮点表示; 例如 1.5 用 16 位浮点值表示 (不过并非所有实现都能高效地找到最小形式). 精度可能存在由实现定义的限制, 这将影响所表示值的精度. 只有在协议中规定了的情况下才应当使用十进制表示.

CBOR 的设计目标是通常提供比 JSON 更紧凑的编码. 可能想到的一种实现策略是在单个缓冲区中原地进行 JSON 到 CBOR 的编码. 该策略需要仔细考虑若干病态情况, 例如某些未使用转义或只使用极少转义、且长度超过 (或远超) 255 字节的字符串, 在 CBOR 中编码为 UTF-8 字符串时可能会膨胀. 类似地, 少数二进制浮点表示可能相对于 JSON 中某些短的十进制表示 (1.1, 1e9) 产生膨胀. 这可能很难做对, 由此产生的任何漏洞都可能被攻击者利用.