เครื่องมือสำหรับนักพัฒนา · ตัวเข้ารหัสและตัวถอดรหัส Base64
atob และ btoa ย่อมาจากอะไร และทำไมพวกเขาถึงเข้าใจแค่ภาษาละติน-1
· พื้นหลัง
base64 javascript ยูนิโค้ด
วันที่ atob และ btoa จาก Netscape และชื่อหมายถึง 'ASCII ถึงไบนารี' และ 'ไบนารีถึง ASCII' โพสต์นี้ครอบคลุมถึงแหล่งที่มา มาตรฐาน WHATWG กำหนดสิ่งเหล่านั้นอย่างไร และเหตุใดพวกเขาจึงไม่เคยเรียนรู้ Unicode
ชื่อฟังก์ชันที่อ่านดูเหมือนตัวพิมพ์ผิด — ความสับสนของชื่อทำให้เกิดและคำตอบบรรทัดเดียว
atob และ btoa เป็นฟังก์ชันในตัว JavaScript ที่เปิดตัวใน Netscape ในปี 1990 ชื่อเหล่านี้เป็นคำย่อ: btoa ย่อมาจาก binary ถึง ASCII และ atob ย่อมาจาก ASCII ไบนารี่ ชื่อนี้สะท้อนถึงอายุและการออกแบบ: ถูกสร้างขึ้นเมื่อไบนารีหมายถึงสตริงของค่าไบต์ (0-255) แทนที่จะเป็น Uint8Array หรือ Buffer ที่ทันสมัยกว่า ตัวช่วยจำที่มักให้ไว้สำหรับชื่อมีความสำคัญน้อยกว่าสัญญาที่สังเกตได้: ฟังก์ชันหนึ่งแมปสตริงไบนารี่กับ Base64 และอีกฟังก์ชันหนึ่งจะกลับรายการ พื้นที่เก็บข้อมูลนี้ไม่ได้บันทึกการตัดสินใจตั้งชื่อดั้งเดิม ดังนั้นบทความนี้จึงหลีกเลี่ยงการนำเสนอนิทานพื้นบ้านเป็นประวัติเบราว์เซอร์ที่มาจากแหล่งที่มา
ฟังก์ชันต่างๆ ต้องการสตริงไบนารี่: หน่วยโค้ดของอักขระแต่ละตัวต้องอยู่ในช่วง 0-255 ซึ่งแสดงถึงหนึ่งไบต์ หากคุณส่งอักขระที่มีหน่วยโค้ดอยู่เหนือ 255 (เช่น อิโมจิหรือตัวอักษรเน้นเสียงจากภาษาลาตินภายนอก 1) ฟังก์ชันจะส่ง InvalidCharacterError หรือสร้างเอาต์พุตที่ไม่ถูกต้องโดยไม่แจ้งให้ทราบ btoa (ไบนารีถึง ASCII) เข้ารหัสสตริงไบนารีเป็น base64
ชื่อนี้แนะนำอะไรและสิ่งที่สัญญาสตริงไบต์พิสูจน์ได้จริง
อินพุตต้องเป็นสตริงโดยที่อักขระแต่ละตัวเป็นไบต์ (หน่วยโค้ด 0-255) btoa(hello) เข้ารหัส ASCII ไบต์เป็น base64 และส่งคืน aGVsbG8= btoa ที่มีตัวอักษร e-acute ดูเหมือนจะใช้ได้เนื่องจากตัวอักษร Latin-1 ที่เขียนไว้ล่วงหน้า e-acute (U+00E9) มีหน่วยโค้ด 233 ซึ่งอยู่ภายใน 0-255 อย่างไรก็ตาม btoa เข้ารหัสเป็นไบต์เดียว 0xE9 ไม่ใช่ UTF-8 ไบต์ 0xC3 0xA9 ที่ e-acute ควรสร้าง ก่อนที่อาร์เรย์ที่พิมพ์จะกลายเป็นที่เก็บไบต์ปกติ JavaScript API จะใช้สตริงที่มีหน่วยโค้ดแทนไบต์ โมเดลนั้นยังคงมองเห็นได้เนื่องจาก btoa ปฏิเสธหน่วยโค้ดที่สูงกว่า 255 ไฟล์เหล่านี้ไม่ได้กำหนดลำดับเหตุการณ์ของผลิตภัณฑ์ที่แน่นอน ขอบเขตความล้มเหลวถูกกำหนดโดยการทดสอบที่ปฏิบัติการได้
การคอร์รัปชั่นแบบเงียบๆ นี้อันตรายมากกว่าข้อผิดพลาด: ผลลัพธ์ดูดีแต่กลับผิด atob (ASCII ถึงไบนารี่) ถอดรหัส base64 กลับไปเป็นสตริงไบนารี่ atob(aGVsbG8=) ส่งคืนสวัสดี เอาต์พุตเป็นสตริงไบนารี่โดยที่หน่วยโค้ดของอักขระแต่ละตัวคือ 0-255 คิดเป็นหนึ่งไบต์ หากคุณต้องการแปลงสิ่งนี้เป็นข้อความ Unicode ที่เหมาะสม คุณต้องตีความไบต์เป็น UTF-8 และถอดรหัสด้วย TextDecoder
โมเดลสตริงไบนารี่แบบเดิม — พฤติกรรมที่สังเกตได้ โดยไม่ต้องอ้างสิทธิ์ประวัติเบราว์เซอร์ที่ไม่ได้รับการยืนยัน
สำหรับ ASCII ขั้นตอนพิเศษนี้ไม่จำเป็น (ASCII เป็นส่วนย่อยของ UTF-8) แต่สำหรับไบต์ที่ไม่ใช่ ASCII ถือว่าจำเป็น atob ไม่ได้ตีความแบบนั้น มันจะส่งคืนไบต์ดิบเป็นสตริงไบนารี่
มาตรฐาน WHATWG (มาตรฐานการดำรงชีวิตสำหรับ Web API) กำหนด atob และ btoa ในข้อกำหนด HTML คำจำกัดความประกอบด้วยอัลกอริธึมการถอดรหัส forgiving-base64 สำหรับ atob โดยจะข้ามช่องว่างและยอมรับช่องว่างภายในที่ขาดหายไป ทำให้สามารถถอดรหัส base64 ในโลกแห่งความเป็นจริง (รวมถึง MIME-wrapped base64 พร้อมการแบ่งบรรทัด) ToolAcre ทำให้ช่องว่างเป็นปกติ URL- เครื่องหมายวรรคตอนที่ปลอดภัยและช่องว่างภายในที่หายไปก่อนที่จะเรียกตัวถอดรหัสเบราว์เซอร์ จากนั้นจะคัดลอกหน่วยโค้ดที่ส่งคืนลงใน Uint8Array และใช้ตัวถอดรหัส UTF-8 ที่ร้ายแรง การรวมกันดังกล่าวจะแยกไวยากรณ์ Base64 ของการให้อภัยออกจากการตีความข้อความที่เข้มงวด
พฤติกรรมปัจจุบันในการใช้งานนี้ - การให้อภัยการทำให้ตัวอักษรเป็นมาตรฐานและการถอดรหัสข้อความ UTF-8 ที่เข้มงวด
ลายเซ็นฟังก์ชันไม่มีการเปลี่ยนแปลง แต่คำจำกัดความมาตรฐานคือสิทธิ์สำหรับสิ่งที่ฟังก์ชันทำ เหตุใด atob และ btoa จึงยอมรับเฉพาะภาษาละติน-1 เนื่องจากเมื่อได้รับการออกแบบในปี 1990 JavaScript ไม่มีวิธีแสดงไบต์โดยตรง (ไม่มี Uint8Array หรือ ArrayBuffer) วิธีเดียวที่จะส่งผ่านไบต์ไปยังฟังก์ชันคือเป็นสตริงโดยที่อักขระแต่ละตัวแทนหนึ่งไบต์
สิ่งนี้เรียกว่าสตริงไบนารี่และทำให้เกิดความสับสนกับมาตรฐานสมัยใหม่ สตริง JavaScript เป็นข้อความ Unicode ไม่ใช่ลำดับของไบต์ การออกแบบทำให้ทั้งสองสับสน: สตริงที่แต่ละหน่วยโค้ด 0-255 เป็นสตริงไบนารี การตั้งชื่อสะท้อนให้เห็นถึงยุคสมัย: ASCII ใน btoa หมายถึงเจ็ดบิตอย่างแท้จริงสำหรับข้อความ ASCII แต่การใช้งานยอมรับไบต์ใดๆ (0-255) การเพิ่มโหมด Unicode ให้กับ btoa โดยตรงจะเปลี่ยนสัญญาสตริงไบต์ที่มีมายาวนานและมีความเสี่ยงในการใช้งานร่วมกันได้ แหล่งที่มาที่ได้รับการตรวจสอบจะเขียน TextEncoder ก่อนการเข้ารหัสแทน บทความนี้สามารถตรวจสอบองค์ประกอบนั้นได้ โดยละเว้นการกล่าวอ้างเกี่ยวกับแรงจูงใจของคณะกรรมการมาตรฐานที่ไม่ได้บันทึกไว้ในที่เก็บข้อมูล
ตัวอย่างการทำงาน: การติดตาม forgiving-base64 บนสตริงที่มีช่องว่างและไม่มีช่องว่างภายใน - สิ่งที่ atob ยอมรับว่าตัวถอดรหัสที่เข้มงวดปฏิเสธ
ทางเลือกสมัยใหม่หลีกเลี่ยงโมเดลสตริงไบนารี่ การเข้ารหัส API ให้ TextEncoder เพื่อแปลงข้อความเป็น UTF-8 ไบต์ และ TextDecoder เพื่อแปลง UTF-8 ไบต์กลับไปเป็นข้อความ
ขณะนี้การเข้ารหัสและถอดรหัส Base64 ได้รับการระบุในข้อกำหนด HTML สำหรับทั้งสตริง (atob และ btoa) และอาร์เรย์ที่พิมพ์ เครื่องมือเข้ารหัสและถอดรหัส Base64 ใช้ TextEncoder และ TextDecoder รอบ ๆ atob และ btoa ดังนั้นคุณจึงสามารถเข้ารหัสและถอดรหัสข้อความ Unicode ได้อย่างปลอดภัยโดยไม่มีข้อจำกัด Latin-1 ค่าที่เว้นวรรคหรือไม่ได้เติมจะสำเร็จเนื่องจากการทำให้เป็นมาตรฐานจะลบช่องว่างและเรียกคืนความยาวบล็อกที่ต้องการ ค่าที่ความยาวที่เคลียร์แล้วเหลือเศษหนึ่งจะถูกปฏิเสธก่อนอะโทบ ความแตกต่างนี้แสดงให้เห็นว่า "การให้อภัย" หมายถึงอะไร: ยอมรับการจัดรูปแบบที่กู้คืนได้ แต่อินพุตที่มีโครงสร้างเป็นไปไม่ได้ไม่ยอมรับ
มาตรฐานที่ใหม่กว่าใช้งานได้กับ Base64 สำหรับอาร์เรย์ที่พิมพ์ — อธิบายในเชิงคุณภาพ พร้อมหมายเหตุเพื่อตรวจสอบการรองรับเบราว์เซอร์ในปัจจุบัน
การจัดการ Unicode ด้วย btoa จำเป็นต้องเข้ารหัสข้อความเป็น UTF-8 ไบต์ก่อน วิธีแก้ปัญหาแบบเก่าคือ btoa(unescape(encodeURIComponent(text))) ซึ่งสร้างความสับสน แต่ใช้งานได้: encodeURIComponent เปอร์เซ็นต์เข้ารหัส UTF-8 ไบต์ unescape แปลงแฝดกลับเป็นอักขระ และ btoa เข้ารหัสสตริงไบนารี่ผลลัพธ์ ใช้งานได้แต่อาศัยฟังก์ชันที่เลิกใช้แล้วและอ่านยาก โค้ดสมัยใหม่ควรใช้ TextEncoder(text).map(byte => String.fromCharCode(byte)) ตามด้วย btoa หรือดีกว่า แปลงเป็น Uint8Array โดยตรงและใช้การเข้ารหัส API
Atob จะไม่ส่งข้อความถึงคุณโดยอัตโนมัติ มันให้ไบนารี่แก่คุณ atob(Y2Fmw6kg8J+YgA==) ส่งคืนสตริงไบนารี่ที่มีไบต์ของข้อความที่เข้ารหัส UTF-8 พร้อม cafe-accent และอิโมจิ หากต้องการกู้คืนข้อความ ให้แปลงสตริงไบนารี่เป็น Uint8Array และส่งผ่านไปยัง TextDecoder(utf-8) เครื่องมือเข้ารหัสและถอดรหัส Base64 ดำเนินการนี้โดยอัตโนมัติ: คุณวางข้อความ จากนั้นจะเข้ารหัสเป็น UTF-8 ไบต์ จากนั้นจึงเข้ารหัสเป็น base64 Typed-array Base64 API มีการพัฒนาในเบราว์เซอร์ต่างๆ แต่แหล่งที่มานี้ไม่ได้ใช้ ขึ้นอยู่กับสิ่งหนึ่งจำเป็นต้องมีการตรวจสอบความเข้ากันได้ในปัจจุบันและแผนสำรอง การแปลงไบต์อาร์เรย์ที่ชัดเจนของ ToolAcre ยังคงสามารถตรวจสอบได้และครอบคลุมโดยชุดทดสอบที่มีอยู่
ทางเลือกอื่นสำหรับ Typed-array กำลังพัฒนา — ตรวจสอบการสนับสนุนเบราว์เซอร์ปัจจุบันก่อนที่จะขึ้นอยู่กับพวกเขา
คุณวาง base64 มันจะถอดรหัสเป็น UTF-8 ไบต์ จากนั้นเป็นข้อความ ขั้นตอนสตริงไบนารี่ระดับกลางถูกซ่อนไว้ เนื่องจากเป็นรายละเอียดการใช้งานของปี 1990 API การทำความเข้าใจ atob และ btoa มีประโยชน์สำหรับการดีบักโค้ดเดิม หรือการทำงานกับ API เก่าที่ส่งสตริงไบนารี่ให้กับคุณ รหัสใหม่ส่วนใหญ่ควรหลีกเลี่ยงโมเดลสตริงไบนารีโดยสิ้นเชิง
หากคุณต้องการเข้ารหัสหรือถอดรหัส base64 เครื่องมือตัวเข้ารหัสและตัวถอดรหัส Base64 จะจัดการ Unicode ได้อย่างถูกต้อง หากคุณกำลังสร้าง API ให้ยอมรับ Uint8Array หรือมุมมองอาเรย์ที่พิมพ์ หรือบันทึกอย่างชัดเจนว่า base64 ของคุณคือ UTF-8 หรือ Latin-1 เมื่อตรวจสอบโค้ดที่ใช้ btoa กับข้อความที่ไม่ใช่ ASCII โดยไม่มี TextEncoder นั่นเป็นจุดบกพร่อง: เอาต์พุตเข้ารหัสไบต์ผิด Node Buffer และรันไทม์ที่ไม่ใช่เบราว์เซอร์จะกำหนด API และกฎการยอมรับที่แตกต่างกัน พวกเขาได้รับการยกเว้นโดยเจตนา การอ้างสิทธิ์ในบทความนี้เกี่ยวข้องกับเบราว์เซอร์ดั้งเดิมและ wrapper ที่นำไปใช้ใน apps/dev, ไม่ใช่ทุกฟังก์ชันที่ชื่อ atob หรือ btoa ในทุกสภาพแวดล้อม
ประเด็นสำคัญ: ฟังก์ชันสองรายการในทศวรรษ 1990 พร้อมสัญญาสตริงไบต์ — วิธีที่ตัวเข้ารหัสและตัวถอดรหัส Base64 ทำการ UTF-8 ก้าวไปรอบๆ สิ่งเหล่านี้อย่างมีสำเนียง CJK และอิโมจิไปกลับ
ชื่อ atob และ btoa เป็นสิ่งประดิษฐ์ที่แปลกประหลาดของการคำนวณในปี 1990 การตั้งชื่อสมัยใหม่จะเป็น base64Encode และ base64Decode และ API จะยอมรับ Uint8Array หรือสตริงที่มีการประกาศการเข้ารหัสที่ชัดเจน แต่ atob และ btoa ยังคงอยู่ในเบราว์เซอร์เพื่อความเข้ากันได้แบบย้อนหลัง การทำความเข้าใจความหมาย (และสิ่งที่พวกเขาทำไม่ได้) ช่วยให้คุณหลีกเลี่ยงความเสียหายที่เกิดขึ้นโดยไม่โต้ตอบเมื่อเข้ารหัสข้อความ Unicode
เครื่องมือเข้ารหัสและถอดรหัส Base64 เชื่อมช่องว่าง: พูดภาษา UTF-8 และ base64 ที่โค้ดสมัยใหม่ต้องการ รูปแบบที่แข็งแกร่งเป็นแบบเรียบเรียง: เข้ารหัสข้อความเป็น UTF-8 ไบต์ แปลงไบต์เป็นสัญญาไบนารีสตริง จากนั้นเรียก btoa ย้อนกลับขั้นตอนเหล่านั้นรอบๆ atob ลองใช้สำเนียง CJK อักขระและอีโมจิ จากนั้นกำหนดให้ใช้ข้อความที่ถอดรหัสเพื่อให้ตรงกับจุดโค้ดต้นฉบับทุกจุด