I nomi atob e btoa può suggerire la normale conversione del testo. Il contratto del loro browser è più ristretto: convertono tra testo Base64 e una stringa i cui valori di carattere rappresentano singoli byte. Quella stringa di byte è un contenitore, non una promessa che il risultato sia testo Unicode leggibile.
Due corde diverse
Le stringhe JavaScript utilizzano le unità di codice UTF-16. Una stringa di byte limita deliberatamente il valore di ciascun carattere a 0–255. btoa('Hello') funziona perché i valori ASCII rientrano in quell'intervallo. btoa('你好') fallisce perché quei caratteri non rientrano in un byte. Anche un carattere che si adatta può essere fuorviante: btoa('é') codifica il singolo byte E9, non i UTF-8 byte C3 A9 previsti da molti servizi.
console.log(btoa('é')); // 6Q== (byte E9)
console.log(btoa(String.fromCharCode(0xc3, 0xa9))); // w6k= (UTF-8)
Inserisci la conversione UTF-8 attorno alle funzioni byte
TextEncoder produce UTF-8 byte dal testo. Dopo aver decodificato Base64, un file fatal TextDecoder converte i byte UTF-8 validi in testo e rifiuta le sequenze non valide invece di sostituirle silenziosamente. Questo piccolo esempio è deliberatamente esplicito in modo che il confine sia visibile.
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); // 中文😊
Non trattare un risultato binario come una stringa interrotta
atob('/w==') rappresenta il byte FF. Non è valido UTF-8 di per sé, ma è un dato binario perfettamente valido. L'azione successiva corretta potrebbe essere un download di byte o una visualizzazione esadecimale, non un diverso trucco di conversione del testo. Eseguendo quella stringa di byte TextEncoder codificherebbe il carattere U+00FF e modificherebbe i byte.
Inoltre, il decodificatore del browser non è un validatore di protocollo completo. Gli spazi bianchi accettati e il riempimento omesso possono differire dai rigidi requisiti dell'applicazione. Se un protocollo richiede la codifica canonica, convalidare separatamente l'alfabeto, il riempimento e i bit non utilizzati. Per file di grandi dimensioni, evitare di distribuire un array di byte completo in String.fromCharCode(...bytes); i limiti del conteggio degli argomenti possono fallire molto prima che il file diventi insolitamente grande.
Leggi i contratti del browser MDN: atob() e MDN: btoa(). L'applicazione dovrebbe decidere se desidera una conversione permissiva, un validatore rigoroso o un flusso di lavoro di conservazione dei file, piuttosto che dare per scontato che si tratti della stessa attività.