繁體中文

開發者工具·Base64編碼器和解碼器

為什麼 btoa() 會拋出表情符號以及如何在 JavaScript 中對 UTF-8 進行 Base64 編碼

· 工作原理

64位基數 統一碼 編碼

Base64編碼前將Unicode字元轉換為UTF-8 bytes
原始 ToolAcre 向量圖

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 損壞的根源。