在我的node.js应用程序中,我做了一个npm安装btoa-atob,这样我就可以使用btoa()和atob()函数,这些函数在客户端javascript中是原生的,但由于某种原因没有包含在node中。新目录出现在我的node_modules文件夹中,它本身和app.js一起在根目录下。然后我确保在包中添加btoa-atob作为依赖项。Json文件,在根目录下。

然而,由于某种原因,它仍然不能工作。

console.log(btoa("Hello World!"));

^应该输出“SGVsbG8gV29ybGQh”到控制台,但是相反,我得到了错误:

Btoa没有定义。

我没有正确地安装吗?我忽略了什么?


当前回答

我发现,尽管上述答案中的shims工作,但它们与桌面浏览器的btoa()和atob()实现的行为不匹配:

const btoa = function(str){ return Buffer.from(str).toString('base64'); }
// returns "4pyT", yet in desktop Chrome would throw an error.
btoa('✓');
// returns "fsO1w6bCvA==", yet in desktop Chrome would return "fvXmvA=="
btoa(String.fromCharCode.apply(null, new Uint8Array([0x7e, 0xf5, 0xe6, 0xbc])));

事实证明,Buffer实例在默认情况下表示/解释UTF-8编码的字符串。相比之下,在桌面Chrome中,你甚至不能输入一个包含latin1范围之外的字符的字符串到btoa(),因为它会抛出一个异常:Uncaught DOMException: Failed to execute 'btoa' on 'Window':要编码的字符串包含latin1范围之外的字符。

因此,你需要显式地将编码类型设置为latin1,以便让你的Node.js shim匹配桌面Chrome的编码类型:

const btoaLatin1 = function(str) { return Buffer.from(str, 'latin1').toString('base64'); }
const atobLatin1 = function(b64Encoded) {return Buffer.from(b64Encoded, 'base64').toString('latin1');}

const btoaUTF8 = function(str) { return Buffer.from(str, 'utf8').toString('base64'); }
const atobUTF8 = function(b64Encoded) {return Buffer.from(b64Encoded, 'base64').toString('utf8');}

btoaLatin1('✓'); // returns "Ew==" (would be preferable for it to throw error because this is undecodable)
atobLatin1(btoa('✓')); // returns "\u0019" (END OF MEDIUM)

btoaUTF8('✓'); // returns "4pyT"
atobUTF8(btoa('✓')); // returns "✓"

// returns "fvXmvA==", just like desktop Chrome
btoaLatin1(String.fromCharCode.apply(null, new Uint8Array([0x7e, 0xf5, 0xe6, 0xbc])));
// returns "fsO1w6bCvA=="
btoaUTF8(String.fromCharCode.apply(null, new Uint8Array([0x7e, 0xf5, 0xe6, 0xbc])));

其他回答

下面是一个简洁的base64编码通用解决方案:

const nodeBtoa = (b) => Buffer.from(b).toString('base64');
export const base64encode = typeof btoa !== 'undefined' ? btoa : nodeBtoa;

我知道这是一个节点应用程序的讨论点,但为了在节点服务器上运行通用JavaScript应用程序,这就是我如何达到这篇文章的,我一直在为我一直在构建的通用/同构react应用程序研究这一点,包abab为我工作。事实上,这是我能找到的唯一有效的解决方案,而不是使用上文提到的Buffer方法(我有打字脚本问题)。

(这个包由jsdom使用,而jsdom又由window包使用。)

回到我的观点;基于此,如果这个函数已经像你提到的那样被编写为npm包,并且有自己的基于W3规范的算法,你可以安装和使用abab包,而不是自己编写基于编码的函数,这些函数可能准确也可能不准确。

——编辑

我开始有奇怪的问题今天编码(不确定为什么它开始发生现在)包abab。它似乎在大多数时候编码正确,但有时在前端编码不正确。花了很长时间尝试调试,但按照建议切换到package base-64,它立即工作了。显然是由于abab的base64算法。

这里发布的解决方案不适用于非ascii字符(即,如果你计划在Node.js和浏览器之间交换base64)。为了让它工作,你必须把输入文本标记为“二进制”。

Buffer.from('Hélló wórld!!', 'binary').toString('base64')

这将得到SOlsbPMgd/NybGQhIQ==。如果您在浏览器中创建atob('SOlsbPMgd/NybGQhIQ=='),它将以正确的方式解码它。它也会在Node.js中通过:

Buffer.from('SOlsbPMgd/NybGQhIQ==', 'base64').toString('binary')

如果你不做“二进制部分”,你会解码错误的特殊字符。

我从btoa npm包的实现中得到它:

想要解码的人:

let decoded = Buffer.from(<encoded string>, 'base64').toString()

因为我来这里寻找解码,最后从这里的答案中找到了答案。

我发现,尽管上述答案中的shims工作,但它们与桌面浏览器的btoa()和atob()实现的行为不匹配:

const btoa = function(str){ return Buffer.from(str).toString('base64'); }
// returns "4pyT", yet in desktop Chrome would throw an error.
btoa('✓');
// returns "fsO1w6bCvA==", yet in desktop Chrome would return "fvXmvA=="
btoa(String.fromCharCode.apply(null, new Uint8Array([0x7e, 0xf5, 0xe6, 0xbc])));

事实证明,Buffer实例在默认情况下表示/解释UTF-8编码的字符串。相比之下,在桌面Chrome中,你甚至不能输入一个包含latin1范围之外的字符的字符串到btoa(),因为它会抛出一个异常:Uncaught DOMException: Failed to execute 'btoa' on 'Window':要编码的字符串包含latin1范围之外的字符。

因此,你需要显式地将编码类型设置为latin1,以便让你的Node.js shim匹配桌面Chrome的编码类型:

const btoaLatin1 = function(str) { return Buffer.from(str, 'latin1').toString('base64'); }
const atobLatin1 = function(b64Encoded) {return Buffer.from(b64Encoded, 'base64').toString('latin1');}

const btoaUTF8 = function(str) { return Buffer.from(str, 'utf8').toString('base64'); }
const atobUTF8 = function(b64Encoded) {return Buffer.from(b64Encoded, 'base64').toString('utf8');}

btoaLatin1('✓'); // returns "Ew==" (would be preferable for it to throw error because this is undecodable)
atobLatin1(btoa('✓')); // returns "\u0019" (END OF MEDIUM)

btoaUTF8('✓'); // returns "4pyT"
atobUTF8(btoa('✓')); // returns "✓"

// returns "fvXmvA==", just like desktop Chrome
btoaLatin1(String.fromCharCode.apply(null, new Uint8Array([0x7e, 0xf5, 0xe6, 0xbc])));
// returns "fsO1w6bCvA=="
btoaUTF8(String.fromCharCode.apply(null, new Uint8Array([0x7e, 0xf5, 0xe6, 0xbc])));