0

我有一个字节数组,我想将其编码为要btoa在浏览器中传递的字符串。这些字节使用完整的 0-255 范围。我遇到了起初似乎是一个错误btoa,但事实证明它是一个错误(或至少是相当意外的行为)与 javascript 的 Array.prototype.join。为了说明这个问题,我将从一些 base64 编码的数据开始:

gACJNqQ0cg==

这可以解码为字节数组,如下所示:

atob('gACJNqQ0cg==').split('').map(c => c.charCodeAt(0))
> [128, 0, 137, 54, 164, 52, 114]

现在,您希望能够反转操作并取回原始字符串:

btoa([128, 0, 137, 54, 164, 52, 114].map(String.fromCharCode).join(''))

但相反,您会得到一个更大的字符串:

gAAAAAEAiQIANgMApAQANAUAcgYA

经过进一步调查,在加入使用 String.fromCharCode 创建的任何字符串时会出现问题:

'Hi'.split('').join('').length
> 2
'Hi'.split('').map(c => c.charCodeAt(0))
> [72, 105]
[72, 105].map(String.fromCharCode).join('').length
> 6
//what?

我在所有尝试过的地方都能看到这种行为:Chrome (60)、Firefox (53) 和 Node (6.9.4)。在浏览器中,您没有简单的替代方案(例如节点) new Buffer(array, 'binary').toString('base64')来解决此问题。如何安全地从字节值数组创建一个字符串,它可以传递给btoa

4

2 回答 2

1

如果您指定一个箭头函数map而不是直接将String.fromCharCode方法传递给它,那么您的代码对我有用:

console.log(btoa([128, 0, 137, 54, 164, 52, 114].map(x => String.fromCharCode(x)).join('')));

于 2017-07-15T04:04:36.543 回答
0

对于这个复杂的问题,我找到了一个简单的解决方法:字符串连接。这是一个例子:

let str = '';
[128, 0, 137, 54, 164, 52, 114].forEach(c => {
    str += String.fromCharCode(c);
});

str.length
> 7
btoa(str)
> 
).join('').length

它可以工作,并且对于不是很大的字符串应该表现得足够好。但我希望看到一个更好、更简洁的解决方案,甚至只是更全面地了解 String.fromCharCode 和 Array.prototype.join 的情况。

于 2017-07-15T03:52:08.553 回答