Base64 en el navegador y Node.js: contrato de un byte, dos API

Utilice TextEncoder en navegadores y Buffer en Node.js, luego pruebe sus salidas con los mismos dispositivos Unicode y binarios.

Un cliente de navegador y un servicio Node.js deberían producir el mismo Base64 para los mismos bytes. No necesitan usar el mismo API para hacerlo. El acuerdo importante es la representación en bytes del texto, el alfabeto y el tratamiento del relleno y la entrada no válida.

Navegador: haga explícito el paso UTF-8

Las funciones tradicionales del navegador operan en cadenas de bytes. Convertir texto Unicode con TextEncoder, luego codifica esos bytes. En la ruta de retorno, reconstruya una matriz de bytes y decodifique UTF-8 explícitamente. Este ejemplo utiliza un bucle para evitar expandir una matriz grande en argumentos de función, aunque un codificador de archivos de producción aún debería usar fragmentos delimitados o un byte apropiado API.

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); // 中文😊

Node.js: mantenga Buffer en el límite de bytes

Buffer.from(text, 'utf8') hace visible la codificación del texto. llamando toString('base64') luego representa esos bytes. La decodificación a Buffer conserva los datos binarios; la conversión inmediata a una cadena UTF-8 solo es apropiada cuando se sabe que la carga útil es texto.

import { Buffer } from 'node:buffer';
const encoded = Buffer.from('中文😊', 'utf8').toString('base64');
console.log(encoded); // 5Lit5paH8J+Yig==
const bytes = Buffer.from(encoded, 'base64');
console.log(new TextDecoder('utf-8', { fatal: true }).decode(bytes)); // 中文😊

El fatal TextDecoder en el ejemplo es deliberado. La conversión de cadena ordinaria Buffer UTF-8 puede insertar caracteres de reemplazo para entradas no válidas. Una visualización de texto exitosa ocultaría que los bytes originales no se pueden representar fielmente.

Acordar la validación por separado

El decodificador Base64 de Node acepta algunos formularios de entrada que una aplicación más estricta puede rechazar. No utilice una conversión Buffer exitosa como prueba de que se proporcionó la representación canónica de un protocolo. Si la sintaxis exacta es importante para firmas, claves de caché o serialización interoperable, verifíquela antes de decodificar.

Para una prueba de regresión compartida, incluya ASCII, chino, emoji, un byte cero, un byte FF y todas las longitudes alrededor de un límite de tres bytes. Compare bytes entre tiempos de ejecución. Pruebe también la salida segura URL con un dispositivo que realmente contenga los caracteres sustituidos; una entrada cuya salida sean solo letras no puede probar que la opción variante funcione.

Al leer archivos en Node, mantenga el Buffer devuelto en lugar de aplicar una codificación de texto al archivo leído. En el navegador, utilice File.arrayBuffer(). Estas pequeñas elecciones de límites evitan la corrupción más accidental. Ver Node.js Buffer para el comportamiento del nodo y MDN: btoa() para el contrato de cadena de bytes del navegador.