los nombres atob y btoa puede sugerir una conversión de texto normal. Su contrato de navegador es más limitado: convierten entre texto Base64 y una cadena cuyos valores de caracteres representan bytes individuales. Esa cadena de bytes es un contenedor, no una promesa de que el resultado sea texto Unicode legible.
Dos cuerdas diferentes
Las cadenas JavaScript utilizan unidades de código UTF-16. Una cadena de bytes restringe deliberadamente el valor de cada carácter entre 0 y 255. btoa('Hello') funciona porque los valores ASCII se ajustan a ese rango. btoa('你好') falla porque esos caracteres no caben en un byte. Incluso un personaje que encaja puede resultar engañoso: btoa('é') codifica el byte único E9, no los UTF-8 bytes C3 A9 esperados por muchos servicios.
console.log(btoa('é')); // 6Q== (byte E9)
console.log(btoa(String.fromCharCode(0xc3, 0xa9))); // w6k= (UTF-8)
Coloque la conversión UTF-8 alrededor de las funciones de bytes
TextEncoder produce UTF-8 bytes de texto. Después de decodificar Base64, un fatal TextDecoder convierte UTF-8 bytes válidos nuevamente en texto y rechaza secuencias no válidas en lugar de reemplazarlas silenciosamente. Este pequeño ejemplo es deliberadamente explícito para que el límite sea visible.
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); // 中文😊
No trate un resultado binario como una cadena rota
atob('/w==') representa el byte FF. No es válido UTF-8 por sí solo, pero son datos binarios perfectamente válidos. La siguiente acción correcta puede ser una descarga de bytes o una vista hexadecimal, no un truco de conversión de texto diferente. Ejecutando esa cadena de bytes TextEncoder codificaría el carácter U+00FF y cambiaría los bytes.
El decodificador del navegador tampoco es un validador de protocolo completo. Los espacios en blanco aceptados y el relleno omitido pueden diferir de los requisitos estrictos de la aplicación. Si un protocolo requiere codificación canónica, valide el alfabeto, el relleno y los bits no utilizados por separado. Para archivos grandes, evite distribuir una matriz de bytes completa en String.fromCharCode(...bytes); Los límites de recuento de argumentos pueden fallar mucho antes de que el archivo se vuelva inusualmente grande.
Lea los contratos del navegador en MDN: atob() y MDN: btoa(). La aplicación debe decidir si quiere una conversión permisiva, un validador estricto o un flujo de trabajo para preservar archivos, en lugar de asumir que son la misma tarea.