JavaScript Base64 receitas para JSON, arquivos e matrizes de bytes

Use receitas JavaScript seguras para UTF-8 para cargas úteis JSON e arquivos selecionados sem tratar acidentalmente dados binários como texto.

O código Base64 útil começa decidindo qual é realmente a entrada. Uma string JavaScript precisa de uma codificação de caracteres; um arquivo já possui bytes; um valor JSON precisa de serialização primeiro. Manter essas etapas visíveis facilita a depuração e evita codificação dupla acidental.

Codifique um pequeno valor JSON

Serialize o valor exatamente uma vez, codifique essa string como UTF-8 e, em seguida, codifique os bytes como Base64. Este exemplo inclui um campo não ASCII para capturar implementações que funcionam apenas com inglês. Destina-se a pequenas cargas úteis; a sequência de bytes temporária aumenta o uso de memória.

const value = { message: '你好', count: 3 };
const text = JSON.stringify(value);
let binary = '';
for (const byte of new TextEncoder().encode(text)) {
  binary += String.fromCharCode(byte);
}
const encoded = btoa(binary);
const bytes = Uint8Array.from(atob(encoded), c => c.charCodeAt(0));
const json = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
console.log(JSON.parse(json).message); // 你好

Uma decodificação Base64 bem-sucedida não garante JSON válido. Trate a decodificação UTF-8 e JSON.parse como pontos de falha separados. Quando o conteúdo decodificado já é uma string contendo JSON, serializá-lo novamente adiciona aspas e escapes; isso altera a carga útil.

Ler um arquivo selecionado como bytes

Para um navegador File, usar arrayBuffer() quando você precisar dos bytes subjacentes. Não use file.text() para uma imagem, arquivo ou arquivo criptografado: sequências de caracteres inválidas podem se tornar caracteres de substituição. Se o seu destino precisar de dados URI, FileReader.readAsDataURL() fornece o wrapper, bem como os dados Base64.

// file is a File selected by the user.
const bytes = new Uint8Array(await file.arrayBuffer());
console.log(bytes.byteLength); // original file size in bytes
// Pass bytes to a byte-oriented encoder, not TextEncoder.

Verificações de ida e volta que detectam erros reais

Compare os bytes decodificados com a matriz de bytes original. A comparação de capturas de tela ou nomes de arquivos não detecta um byte alterado. Inclui entrada vazia, todos os valores de bytes de 0 a 255, texto chinês, emoji e uma carga útil cujo comprimento deixa um ou dois bytes no grupo final. Para um lote de arquivos, preserve o nome, o tamanho e o resultado de cada arquivo de forma independente para que um erro não possa substituir outra saída bem-sucedida.

Mantenha as conversões locais, a menos que seu fluxo de trabalho chame intencionalmente um API. Uma solicitação de rede contendo a saída codificada ainda envia os dados subjacentes de forma reversível. Para o comportamento da string de bytes e a limitação Unicode da função do navegador, consulte MDN: btoa().