ไทย

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

atob และ btoa ย่อมาจากอะไร และทำไมพวกเขาถึงเข้าใจแค่ภาษาละติน-1

· พื้นหลัง

base64 javascript ยูนิโค้ด

รูปแบบหน่วยไบต์สตริงไบนารี btoa และ atob แตกต่างจากข้อความ Unicode
ภาพประกอบเวกเตอร์ต้นฉบับ ToolAcre

วันที่ 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 อักขระและอีโมจิ จากนั้นกำหนดให้ใช้ข้อความที่ถอดรหัสเพื่อให้ตรงกับจุดโค้ดต้นฉบับทุกจุด