ไทย

เครื่องมือสำหรับนักพัฒนา · ตัวเข้ารหัสและตัวถอดรหัส Base64

เหตุใด btoa() จึงขว้างอิโมจิและวิธีเข้ารหัส Base64 UTF-8 ใน JavaScript

· มันทำงานอย่างไร

base64 ยูนิโค้ด การเข้ารหัส

อักขระ Unicode แปลงเป็น UTF-8 ไบต์ก่อนการเข้ารหัส Base64
ภาพประกอบเวกเตอร์ต้นฉบับ ToolAcre

btoa() ยอมรับเฉพาะอักขระที่มีขนาดไม่เกิน U+00FF ดังนั้นข้อความที่มีการเน้นเสียง CJK และการโยนอีโมจิ โพสต์นี้แสดงสิ่งที่ฟังก์ชันคาดหวังจริง ๆ และวิธีที่ TextEncoder ทำให้คุณได้รับสตริง UTF-8 Base64 ที่ถูกต้อง

เหตุใด btoa จึงสามารถใช้ Unicode ได้ และเข้ารหัสสำเนียงผิดโดยไม่ตั้งใจ

การเรียก btoa("😀") จะพ่น InvalidCharacterError เนื่องจากอิโมจิไม่สามารถใส่ลงในหน่วยโค้ดขนาดไบต์เดียวได้ ข้อผิดพลาดย่อยคือ btoa("é"): คำนำหน้า é คือ U+00E9 ต่ำกว่า 256 ดังนั้น btoa ยอมรับ แต่เข้ารหัส Latin-1 byte E9 ไม่ใช่ UTF-8 ไบต์ C3 A9 สำเนียงที่มองเห็นได้แบบเดียวกันที่เขียนเป็น e บวกเครื่องหมายรวมสามารถส่งได้เนื่องจากเครื่องหมายอยู่นอกช่วงที่ยอมรับ การจดชวเลขของสมุดงาน "an Accent Throws" จำเป็นต้องมีคุณสมบัตินี้: สตริงอาจทำงานล้มเหลวอย่างดังหรือเงียบๆ ทำให้เกิดไบต์ที่ไม่ถูกต้อง

สิ่งที่ btoa() เข้ารหัสจริงๆ: สตริงไบนารี่ของหน่วยโค้ด 0–255 — เหตุใดฟังก์ชันจึงได้รับการออกแบบโดยใช้ภาษาละติน-1 bytes แทนที่จะเป็นข้อความ Unicode

btoa ใช้ "สตริงไบนารี": หน่วยโค้ดอักขระ JavaScript แต่ละหน่วยต้องอยู่ในช่วง 0–255 และย่อมาจากหนึ่งไบต์ ไม่เข้าใจการเข้ารหัสข้อความ Unicode ภาษา หรือการทำให้เป็นมาตรฐาน อีโมจิดวงดาวแสดงด้วยหน่วยโค้ดตัวแทน UTF-16 สองหน่วย ซึ่งทั้งสองหน่วยมีขนาดใหญ่กว่า 255 มาก ดังนั้นการส่งสตริง JavaScript แบบดิบโดยตรงจึงไม่สามารถทำงานได้ ถือว่าเอาต์พุตเป็นการเข้ารหัสไบต์ ไม่ใช่อักขระนามธรรม

UTF-8 อันดับแรก Base64 วินาที — เพราะเหตุใดข้อความจึงต้องกลายเป็นไบต์ก่อนที่จะใช้ตัวอักษร Base64 ใดๆ

TextEncoder เปลี่ยนสตริง JavaScript เป็นลำดับไบต์ UTF-8 ก่อน จากนั้นเปลี่ยนแต่ละไบต์ให้เป็นอักขระไบนารี่สตริงและส่งสตริงไบนารี่นั้นไปที่ btoa หรือใช้ API อื่นที่ยอมรับไบต์โดยตรง สำหรับการถอดรหัส atob จะส่งกลับสตริงไบนารี่ กู้คืนค่าไบต์และมอบให้กับ TextDecoder("utf-8") ToolAcre ใช้ตัวถอดรหัสที่เข้มงวดซึ่งปฏิเสธ UTF-8 ที่มีรูปแบบไม่ถูกต้อง แทนที่จะแทรกอักขระแทนที่โดยไม่แจ้งให้ทราบ

ตัวอย่างการทำงาน: การเข้ารหัส 'cafe 😀' ด้วย TextEncoder และ btoa - ลำดับไบต์ สตริงไบนารี่ระดับกลาง และเอาต์พุตสุดท้าย

สำหรับคาเฟ่ข้อความตามตัวอักษร 😀 ไบต์ UTF-8 คือ 63 61 66 C3 A9 20 F0 9F 98 80 ในเลขฐานสิบหก: ASCII c-a-f, สองไบต์สำหรับ é ช่องว่าง และสี่ไบต์สำหรับอิโมจิ Base64 ของสิบไบต์นี้คือ Y2Fmw6kg8J+YgA== ช่องว่างภายในและตัวอักษรอธิบายเฉพาะไบต์เท่านั้น พวกเขาไม่ได้ติดป้ายภาษา เปรียบเทียบความล้มเหลวโดยตรงของ btoa("cafe 😀") กับโหมด UTF-8 ของ ToolAcre จากนั้นถอดรหัสผลลัพธ์และตรวจสอบสำเนียงที่มองเห็นได้แบบเดียวกันและอีโมจิยังคงอยู่

เคล็ดลับ unescape(encodeURIComponent()) แบบเก่าและทำไมมันถึงเป็นแฮ็ก — มันทำอะไรภายใต้ประทุนและทำไมมันถึงท้อแท้

วิธีแก้ปัญหาในอดีตคือ btoa(unescape(encodeURIComponent(text))) encodeURIComponent เปอร์เซ็นต์เข้ารหัส UTF-8 และ unescape บรรจุเปอร์เซ็นต์ triplets ใหม่เป็นหน่วยโค้ดเดียว แต่ unescape เลิกใช้แล้ว อ่านยาก และอึดอัดกับตัวแทนที่มีรูปแบบเดียวที่ผิดรูปแบบ ทำให้ Conversion ดูเหมือนกำลังประมวลผล URL แม้ว่าจะไม่มี URL ก็ตาม TextEncoder ระบุขอบเขตที่ต้องการอย่างชัดเจน: ข้อความกลายเป็นไบต์หนึ่งครั้ง และ Base64 จะทำงานหลังจากนั้นเท่านั้น

การถอดรหัสในอีกด้านหนึ่ง — จับคู่ atob กับ TextDecoder เพื่อให้การเดินทางไปกลับไม่มีการสูญเสีย

หลังจาก atob อย่าเรียก decodeURIComponent กับไบต์ไบนารี่ที่กำหนดเองและหวังว่ามันจะกลายเป็นข้อความ แปลงรหัสอักขระเป็น Uint8Array และส่งผ่าน TextDecoder ในตัวอย่าง cafe 😀 ผลลัพธ์คือลำดับสิบไบต์ UTF-8 ดั้งเดิม จากนั้นจึงเป็นสตริงดั้งเดิม หาก Base64 ถอดรหัสเป็นรูปภาพหรือไบต์ของไฟล์บีบอัด อาจไม่สามารถแสดงข้อความ UTF-8 ที่ถูกต้องได้เลย ToolAcre รายงานว่าแทนที่จะแสร้งทำเป็นว่าข้อมูลไบนารีเป็นร้อยแก้วที่สามารถอ่านได้

สิ่งนี้ไม่ครอบคลุม — การเข้ารหัสไฟล์และ binary-blob, ตัวแปร base64url และการสตรีมอินพุตขนาดใหญ่

คำอธิบายนี้เกี่ยวข้องกับข้อความที่เข้ารหัสเป็น UTF-8 ไฟล์และ Blob Base64, Base64url สำหรับเซ็กเมนต์ JWT และการเข้ารหัสข้อมูลหลายกิกะไบต์แบบเพิ่มหน่วยมีอินเทอร์เฟซหรือความต้องการหน่วยความจำที่แตกต่างกัน Base64 ยังไม่เข้ารหัสโทเค็น ใครก็ตามที่ถือโทเค็นนั้นสามารถถอดรหัสไบต์ได้ ตัวถอดรหัสสามารถยอมรับช่องว่างภายในและช่องว่างทั่วไปที่ขาดหายไป แต่ความสามารถในการทำงานร่วมกันยังคงขึ้นอยู่กับการรู้ว่าเพย์โหลดเป็นข้อความหรือข้อมูลไบนารีที่กำหนดเอง

ประเด็นสำคัญ: เข้ารหัสไบต์ ไม่ใช่สตริง และตรวจสอบการเดินทางไปกลับ — ตัวเข้ารหัสและตัวถอดรหัส Base64 ทำขั้นตอน UTF-8 ให้คุณอย่างไร สำเนียง CJK และอีโมจิยังคงอยู่

เข้ารหัสไบต์ ไม่ใช่สตริง JavaScript แบบดิบ จากนั้นตรวจสอบการเดินทางไปกลับ ตัวเข้ารหัสและตัวถอดรหัส Base64 ดำเนินการตามขั้นตอน TextEncoder และ TextDecoder สำหรับคุณในขณะที่เก็บข้อความที่วางไว้ในเบราว์เซอร์ RFC 4648 ระบุตัวอักษรและช่องว่างภายใน; UTF-8 ให้สัญญาอักขระเป็นไบต์แยกต่างหาก การผสมสองชั้นเหล่านี้เป็นรากฐานของทั้ง InvalidCharacterError และความเสียหายแบบ Latin-1 แบบเงียบ