开发者工具·Base64编码器和解码器
为什么 btoa() 会抛出表情符号以及如何在 JavaScript 中对 UTF-8 进行 Base64 编码
· 工作原理
64位基数 统一码 编码
btoa() 只接受 U+00FF 以内的字符,因此重音文本、CJK 和表情符号会抛出异常。这篇文章展示了该函数实际期望的内容以及 TextEncoder 如何为您获取正确的 UTF-8 Base64 字符串。
为什么 btoa 可以使用 Unicode,并默默地对口音进行错误编码
调用 btoa("😀") 会抛出 InvalidCharacterError,因为表情符号无法放入单个字节大小的代码单元中。一个更微妙的错误是 btoa("é"):预组合的 é 是 U+00E9,低于 256,因此 btoa 接受它,但编码 Latin-1 byte E9,而不是 UTF-8 bytes C3 A9。写成 e 加上组合标记的相同可见重音可能会抛出错误,因为该标记超出了可接受的范围。工作簿的速记“重音抛出”需要这样的限定:字符串可能会大声失败,也可能悄悄地产生错误的字节。
btoa() 真正编码的内容:代码单元 0-255 的二进制字符串 — 为什么该函数是围绕 Latin-1 bytes 而不是 Unicode 文本设计的
btoa 使用“二进制字符串”:每个 JavaScript 字符代码单元必须在 0-255 范围内,代表一个字节。它不理解 Unicode 文本编码、语言或规范化。星体表情符号由两个 UTF-16 代理代码单元表示,两者都远大于 255,因此直接发送原始 JavaScript 字符串无法工作。将输出视为字节编码,而不是抽象字符编码。
首先是 UTF-8,其次是 Base64 — 为什么文本必须在任何 Base64 字母表应用之前变成字节
TextEncoder 首先将 JavaScript 字符串转换为其 UTF-8 byte 序列。然后将每个字节转换为二进制字符串字符并将该二进制字符串传递给 btoa,或者使用另一个直接接受字节的 API。对于解码,atob 返回二进制字符串;恢复其字节值并将其提供给 TextDecoder("utf-8")。 ToolAcre 使用严格的解码器,拒绝格式错误的 UTF-8,而不是默默地插入替换字符。
工作示例:使用 TextEncoder 和 btoa 编码“café 😀”——字节序列、中间二进制字符串和最终输出
对于文本咖啡馆 😀,UTF-8 bytes 为十六进制的 63 61 66 C3 A9 20 F0 9F 98 80:ASCII c-a-f,两个字节用于 é,一个空格和四个字节用于表情符号。这十个字节的Base64为Y2Fmw6kg8J+YgA==。填充和字母表仅描述字节;他们不标记语言。将直接 btoa("café 😀") 失败与 ToolAcre 的 UTF-8 模式进行比较,然后解码其结果并验证相同的可见口音和表情符号是否存在。
旧的 unescape(encodeURIComponent()) 技巧以及为什么它是一个 hack — 它在幕后做了什么以及为什么不鼓励它
历史上的解决方法是 btoa(unescape(encodeURIComponent(text)))。 encodeURIComponent 对 UTF-8 进行百分比编码,并且 unescape 将百分比三元组重新打包为单个代码单元,但是 unescape 已被弃用,难以阅读,并且在格式错误的单独代理项周围显得很尴尬。即使不存在 URL,它也会使转换看起来像 URL 处理。 TextEncoder 清楚地说明了预期的边界:文本一旦成为字节,Base64 仅在此之后运行。
另一端解码 — 将 atob 与 TextDecoder 配对,以便往返过程无损
atob之后,不要对任意二进制字节调用decodeURIComponent并希望它们变成文本。将字符代码转换为 Uint8Array 并将其传递给 TextDecoder。在咖啡馆😀示例中,结果是原始的十字节 UTF-8 序列,然后是原始字符串。如果 Base64 解码为图像或压缩文件字节,它可能根本不代表有效的 UTF-8 文本; ToolAcre 报告称,二进制数据不是假装的可读散文。
这不包括文件和二进制 blob 编码、base64url 变体和流式传输大型输入
此解释涉及编码为 UTF-8 的文本。文件和 Blob Base64、JWT 段的 Base64url 以及多 GB 数据的增量编码具有不同的接口或内存需求。 Base64 也不加密令牌:任何持有它的人都可以解码字节。解码器可以接受常见的缺失填充和空格,但互操作性仍然取决于了解有效负载是文本还是任意二进制数据。
要点:编码字节,而不是字符串,并检查往返行程 — Base64 编码器和解码器如何为您执行 UTF-8 步骤,以便重音、CJK 和表情符号得以幸存
对字节进行编码,而不是原始 JavaScript 字符串,然后检查往返行程。 Base64 编码器和解码器为您执行 TextEncoder 和 TextDecoder 步骤,同时将粘贴的文本保留在浏览器中。 RFC 4648 指定了字母表和填充; UTF-8 提供单独的字符到字节合约。混合这两层是 InvalidCharacterError 和安静的 Latin-1 损坏的根源。