【问题标题】:CBOR encoding issue on format of keys关于密钥格式的 CBOR 编码问题
【发布时间】:2021-12-11 15:09:00
【问题描述】:

在 javascript(不使用节点)上,当使用库 (https://github.com/paroga/cbor-js) 进行 CBOR 编码和在线使用 CBOR (https://cbor.me/) 时,我面临不同的结果。请注意,即使使用更新的 CBOR 库,结果也是相同的。

例如设置一个对象,例如:

const initial = { 1: "John", "-2": 456 };

使用 CBOR 在线编码给出:a201644a6f686e622d321901c8。详情如下:

A2             # map(2)
   01          # unsigned(1)
   64          # text(4)
      4A6F686E # "John"
   62          # text(2)
      2D32     # "-2"
   19 01C8     # unsigned(456)

现在在 javascript 上使用 CBOR 库进行编码会产生不同的结果:a26131644a6f686e622d321901c8

在在线 CBOR 上解码以上十六进制时,我得到:{“1”:“John”,“-2”:456}。结果几乎与常量 'initial' 相同,只是键 1 现在带有引号 (")。

CBOR 在线将我的十六进制值重新格式化为更“可读”的视图:

A2             # map(2)
   61          # text(1)
      31       # "1"
   64          # text(4)
      4A6F686E # "John"
   62          # text(2)
      2D32     # "-2"
   19 01C8     # unsigned(456)

请看下面我的 Javascript 代码:

    //convert an array of bytes (as 8 bits) to string of Hex. ensure that Hex value are not return with 1 digit but 2 digits. ie '01' instead of '1'
    function toHexString(byteArray) {
      var s = '';
      byteArray.forEach(function(byte) {
        s += ('0' + (byte & 0xFF).toString(16)).slice(-2);
      });
      return s;
    }

    const initial = { 1: "John", "-2": 456 };
    
    var encoded = CBOR.encode(initial);
    var encodedHex = toHexString(Array.from(new Uint8Array(encoded)));
    console.log ( encodedHex );

我可以手动替换特定的十六进制值,例如:

“61 31 64”替换为“01 64”

但不喜欢这样做,因为列表可能对涵盖所有可能的选项很重要。

是否有人有解决方法,因为我需要我的结果是 'a201644a6f686e622d321901c8' 而不是 'a26131644a6f686e622d321901c8'?

【问题讨论】:

    标签: javascript json cbor


    【解决方案1】:

    Javascript 中的对象键

    CBOR specification, section 5.6 说:

    在需要与基于 JSON 的应用程序交互的应用程序中,通过将键限制为仅文本字符串来简化转换

    确实,cbor-js 包使用了Object.keys 方法here,它将所有键作为字符串返回。 Javascript 不区分数字及其字符串值,并将{'1':1, 1:2} 视为{'1':2}(而cbor.me 将其视为具有两个条目的映射)。

    修改cbor-js的解决方案

    您的示例表明您希望 非负 数字键被 CBOR 视为数字。这可以通过cbor-js 源代码上的以下补丁来实现:

    diff --git a/cbor.js b/cbor.js
    --- a/cbor.js
    +++ b/cbor.js
    @@ -164,7 +164,10 @@ function encode(value) {
               writeTypeAndLength(5, length);
               for (i = 0; i < length; ++i) {
                 var key = keys[i];
    -            encodeItem(key);
    +            if (isNaN(key) || Number(key) < 0)
    +              encodeItem(key);
    +            else
    +              encodeItem(Number(key));
                 encodeItem(value[key]);
               }
             }
    

    有了这个改变,Node.js 给了我

    > Buffer.from(cbor.encode({1:'John','-2':456})).toString('hex'))
    'a201644a6f686e622d321901c8'
    

    或者您甚至可以通过在上面的补丁中省略 || Number(key) &lt; 0 来将负数字键视为数字。这给了

    > Buffer.from(cbor.encode({1:'John','-2':456})).toString('hex'))
    'a201644a6f686e211901c8'
    A2             # map(2)
       01          # unsigned(1)
       64          # text(4)
          4A6F686E # "John"
       21          # negative(1)
       19 01C8     # unsigned(456)
    

    解决方案cbor

    cbor-js 不同,cbor 包允许您对 Javascript Map 进行编码,以区分数字键和字符串键:

    > Buffer.from(cbor.encode(new Map().set(1,'John').set(-2,456))).toString('hex')
    'a201644a6f686e211901c8'
    

    【讨论】:

    • 就像一个魅力!谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-29
    • 1970-01-01
    • 2022-12-03
    • 1970-01-01
    • 2018-10-19
    • 1970-01-01
    • 2014-05-24
    相关资源
    最近更新 更多