Waarom atob() bytes retourneert en btoa() bepaalde tekst afwijst

Begrijp JavaScript binaire strings, tekenbereikfouten en de UTF-8 stap die nodig is rond atob en btoa.

De namen atob en btoa kan gewone tekstconversie voorstellen. Hun browsercontract is beperkter: ze converteren tussen Base64 tekst en een string waarvan de karakterwaarden individuele bytes vertegenwoordigen. Die bytestring is een container, geen belofte dat het resultaat leesbare Unicode-tekst is.

Twee verschillende snaren

JavaScript tekenreeksen gebruiken UTF-16 code-eenheden. Een bytestring beperkt opzettelijk elke tekenwaarde tot 0–255. btoa('Hello') werkt omdat ASCII-waarden in dat bereik passen. btoa('你好') mislukt omdat die tekens niet in één byte passen. Zelfs een personage dat wel past, kan misleidend zijn: btoa('é') codeert de enkele byte E9, niet de UTF-8 bytes C3 A9 die door veel services worden verwacht.

console.log(btoa('é')); // 6Q== (byte E9)
console.log(btoa(String.fromCharCode(0xc3, 0xa9))); // w6k= (UTF-8)

Plaats UTF-8 conversie rond de bytefuncties

TextEncoder produceert UTF-8 bytes uit tekst. Na het decoderen van Base64, een fataal TextDecoder converteert geldige UTF-8 bytes terug naar tekst en verwerpt ongeldige reeksen in plaats van ze stil te vervangen. Dit kleine voorbeeld is opzettelijk expliciet gemaakt, zodat de grens zichtbaar is.

const text = '中文😊';
const bytes = new TextEncoder().encode(text);
let binary = '';
for (const byte of bytes) binary += String.fromCharCode(byte);
const encoded = btoa(binary);
console.log(encoded); // 5Lit5paH8J+Yig==
const decodedBytes = Uint8Array.from(atob(encoded), c => c.charCodeAt(0));
const decoded = new TextDecoder('utf-8', { fatal: true }).decode(decodedBytes);
console.log(decoded); // 中文😊

Beschouw een binair resultaat niet als een gebroken string

atob('/w==') vertegenwoordigt de byte FF. Het is op zichzelf geen geldige UTF-8, maar het zijn volkomen geldige binaire gegevens. De juiste volgende actie kan een bytedownload of hexadecimale weergave zijn, en niet een andere tekstconversietruc. Die bytereeks doorlopen TextEncoder zou het teken U+00FF coderen en de bytes veranderen.

De browserdecoder is ook geen volledige protocolvalidator. Geaccepteerde witruimte en weggelaten opvulling kunnen afwijken van strikte toepassingsvereisten. Als een protocol canonieke codering vereist, valideer dan het alfabet, de opvulling en de ongebruikte bits afzonderlijk. Voorkom bij grote bestanden het verspreiden van een volledige byte-array in String.fromCharCode(...bytes); Limieten voor het aantal argumenten kunnen mislukken lang voordat het bestand ongewoon groot wordt.

Lees de browsercontracten in MDN: atob() en MDN: btoa(). De toepassing moet beslissen of zij een tolerante conversie, een strikte validator of een workflow voor het bewaren van bestanden wil, in plaats van aan te nemen dat dit dezelfde taak is.