[CÓDIGO] 6 min de leitura

[CÓDIGO] Base64 em JavaScript

Exemplos práticos de JavaScript para codificação e decodificação Base64 com APIs modernas de navegador.

Janeiro 2025 | development

// CODIFICAÇÃO E DECODIFICAÇÃO BÁSICA

JavaScript fornece funções integradas para operações Base64. As funções btoa() e atob() lidam com codificação e decodificação básica:

Essas funções funcionam muito bem para texto ASCII, mas requerem tratamento especial para caracteres Unicode.

// Codificação Base64 básica
const text = 'Olá Mundo';
const encoded = btoa(text);
console.log(encoded); // T2zDoSBNdW5kbw==

// Decodificação Base64 básica
const decoded = atob(encoded);
console.log(decoded); // Olá Mundo

// Verificar se string é Base64 válido
function isValidBase64(str) {
    try {
        return btoa(atob(str)) === str;
    } catch (err) {
        return false;
    }
}

// SUPORTE UNICODE

Para strings Unicode, precisamos converter primeiro para bytes UTF-8. Navegadores modernos fornecem APIs TextEncoder e TextDecoder:

Esta abordagem trata corretamente emojis, caracteres internacionais e outros conteúdos Unicode.

// Codificação Base64 segura para Unicode
function encodeBase64(str) {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(str);
    const binary = String.fromCharCode(...bytes);
    return btoa(binary);
}

// Decodificação Base64 segura para Unicode
function decodeBase64(base64) {
    const binary = atob(base64);
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) {
        bytes[i] = binary.charCodeAt(i);
    }
    const decoder = new TextDecoder();
    return decoder.decode(bytes);
}

// Exemplo com emoji
const emoji = 'Olá 👋 Mundo 🌍';
const encoded = encodeBase64(emoji);
const decoded = decodeBase64(encoded);
console.log(decoded); // Olá 👋 Mundo 🌍

// TRATAMENTO DE ARQUIVOS

Converter arquivos para Base64 é comum para uploads e URIs de dados. Use a API FileReader para processamento de arquivos do lado do cliente:

Isso cria URIs de dados que podem ser incorporados diretamente em HTML ou enviados para APIs.

// Converter arquivo para URI de dados Base64
function fileToBase64(file) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result);
        reader.onerror = error => reject(error);
        reader.readAsDataURL(file);
    });
}

// Uso com input de arquivo
document.getElementById('fileInput').addEventListener('change', async (e) => {
    const file = e.target.files[0];
    if (file) {
        try {
            const base64 = await fileToBase64(file);
            console.log(base64);
            // Resultado: data:image/png;base64,iVBORw0KGgoAAAA...
        } catch (error) {
            console.error('Erro:', error);
        }
    }
});

// BASE64 SEGURO PARA URL

Base64 padrão usa caracteres + e / que precisam de codificação URL. Base64 seguro para URL substitui estes por - e _:

Isso é essencial para tokens, IDs e outros dados transmitidos via URLs.

// Converter para Base64 seguro para URL
function toUrlSafeBase64(base64) {
    return base64
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
}

// Converter de Base64 seguro para URL
function fromUrlSafeBase64(urlSafeBase64) {
    let base64 = urlSafeBase64
        .replace(/-/g, '+')
        .replace(/_/g, '/');
    
    // Adicionar preenchimento se necessário
    const padding = 4 - (base64.length % 4);
    if (padding !== 4) {
        base64 += '='.repeat(padding);
    }
    
    return base64;
}

// Exemplo
const text = 'Teste de codificação segura para URL';
const encoded = btoa(text);
const urlSafe = toUrlSafeBase64(encoded);
console.log(urlSafe); // VGVzdGUgZGUgY29kaWZpY2HDp8OjbyBzZWd1cmEgcGFyYSBVUkw

// STREAMING DE DADOS GRANDES

Para arquivos grandes ou fluxos de dados, processe em pedaços para evitar problemas de memória:

Esta abordagem previne congelamento do navegador e trata grandes conjuntos de dados eficientemente.

// Codificação Base64 baseada em streaming
class Base64Encoder {
    constructor() {
        this.buffer = '';
    }
    
    encode(chunk) {
        this.buffer += chunk;
        const completeBytes = Math.floor(this.buffer.length / 3) * 3;
        const toEncode = this.buffer.slice(0, completeBytes);
        this.buffer = this.buffer.slice(completeBytes);
        
        return btoa(toEncode);
    }
    
    flush() {
        if (this.buffer.length > 0) {
            const result = btoa(this.buffer);
            this.buffer = '';
            return result;
        }
        return '';
    }
}

// Uso
const encoder = new Base64Encoder();
let result = '';
result += encoder.encode('Primeiro pedaço');
result += encoder.encode(' Segundo pedaço');
result += encoder.flush();
console.log(result);

// TRATAMENTO DE ERROS

Sempre implemente tratamento de erro adequado para operações Base64:

Tratamento robusto de erros previne crashes de aplicação e fornece melhor experiência do usuário.

// Operações Base64 seguras com tratamento de erro
function safeEncode(input) {
    try {
        if (typeof input !== 'string') {
            throw new Error('Entrada deve ser uma string');
        }
        return btoa(input);
    } catch (error) {
        console.error('Erro de codificação:', error.message);
        return null;
    }
}

function safeDecode(base64) {
    try {
        // Validar formato Base64
        if (!/^[A-Za-z0-9+/]*={0,2}$/.test(base64)) {
            throw new Error('Formato Base64 inválido');
        }
        return atob(base64);
    } catch (error) {
        console.error('Erro de decodificação:', error.message);
        return null;
    }
}

// Uso
const encoded = safeEncode('Olá Mundo');
const decoded = safeDecode(encoded);
if (encoded && decoded) {
    console.log('Sucesso:', decoded);
}