Codifica Base64 in JavaScript: Guida Completa

·Front-end & Node.js Developer·Revisionato daSophie Laurent·Pubblicato

Usa il Codificatore Base64 Online gratuito direttamente nel tuo browser — nessuna installazione.

Prova Codificatore Base64 Online online →

Quando incorpori un'immagine in una URI dati CSS, passi credenziali in un'intestazione HTTP Authorization, o memorizzi un certificato binario in una variabile d'ambiente, hai bisogno di codificare dati JavaScript in Base64 in modo affidabile sia nel browser che in Node.js. JavaScript fornisce due API integrate distinte:btoa() per gli ambienti browser (disponibile anche in Node.js 16+) e Buffer.from() per Node.js — ciascuna con vincoli diversi riguardo a Unicode, dati binari e sicurezza degli URL. Per una codifica rapida senza scrivere codice, il Codificatore Base64 di ToolDeck lo fa istantaneamente nel browser. Questa guida copre entrambi gli ambienti con esempi pronti per la produzione: gestione di Unicode, varianti URL-safe, codifica di file e risposte API, utilizzo da CLI, e i quattro errori che causano bug ricorrenti nelle basi di codice reali.

  • btoa() è nativo del browser e disponibile globalmente in Node.js 16+, ma accetta solo Latin-1 (punti di codice 0–255) — l'input Unicode lancia una DOMException
  • Buffer.from(text, "utf8").toString("base64") è l'equivalente Node.js e gestisce Unicode nativamente senza passaggi aggiuntivi
  • Il Base64 URL-safe sostituisce + → -, / → _, e rimuove il padding = — usa Buffer.from().toString("base64url") in Node.js 18+ per una soluzione in una riga
  • Per i dati binari (ArrayBuffer, Uint8Array, file), usa Buffer in Node.js o l'approccio arrayBuffer() + Uint8Array nel browser — mai response.text()
  • Uint8Array.prototype.toBase64() (TC39 Stage 3) è già disponibile in Node.js 22+ e Chrome 130+ e unificherà entrambi gli ambienti

Cos'è la Codifica Base64?

Base64 converte dati binari arbitrari in una stringa costruita da 64 caratteri ASCII stampabili: A–Z, a–z, 0–9, +, e /. Ogni 3 byte di input vengono mappati a esattamente 4 caratteri Base64; se la lunghezza dell'input non è un multiplo di 3, vengono aggiunti uno o due caratteri di padding =. L'output codificato è sempre circa il 33% più grande dell'originale.

Base64 nonè crittografia — non fornisce riservatezza. Chiunque disponga della stringa codificata può decodificarla con una singola chiamata di funzione. Il suo scopo è la sicurezza del trasporto: molti protocolli e formati di archiviazione sono stati progettati per testo ASCII a 7 bit e non possono gestire byte binari arbitrari. Base64 colma questa lacuna. I casi d'uso comuni in JavaScript includono le URI dati per l'incorporamento di asset, le intestazioni HTTP Basic Auth, i segmenti di token JWT, gli allegati MIME delle email, e l'archiviazione di blob binari nelle API JSON.

Before · text
After · text
deploy-bot:sk-prod-a7f2c91e4b3d8
ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=

btoa() — La funzione di codifica nativa del browser

btoa()(binary-to-ASCII) è disponibile nei browser da IE10 ed è diventata una globale in Node.js 16.0 nell'ambito dell'iniziativa di compatibilità WinterCG. Funziona anche nativamente in Deno, Bun e Cloudflare Workers. Non è richiesto alcun import.

La funzione accetta un singolo argomento stringa e restituisce la sua forma codificata in Base64. La controparte simmetrica atob()(ASCII-to-binary) la decodifica. Entrambe sono sincrone ed eseguono con memoria costante relativa alla dimensione dell'input.

Esempio minimo funzionante

JavaScript (browser / Node.js 16+)
// Encoding an API credential pair for an HTTP Basic Auth header
const serviceId  = 'deploy-bot'
const apiKey     = 'sk-prod-a7f2c91e4b3d8'

const credential = btoa(`${serviceId}:${apiKey}`)
// → 'ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg='

const headers = new Headers({
  Authorization: `Basic ${credential}`,
  'Content-Type': 'application/json',
})

console.log(headers.get('Authorization'))
// Basic ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=

Decodifica con atob()

JavaScript
// Round-trip: encode, transmit, decode
const payload = 'service:payments region:eu-west-1 env:production'

const encoded = btoa(payload)
const decoded = atob(encoded)

console.log(encoded)
// c2VydmljZTpwYXltZW50cyByZWdpb246ZXUtd2VzdC0xIGVudjpwcm9kdWN0aW9u

console.log(decoded === payload) // true
Nota:btoa() e atob() fanno parte della WinterCG Minimum Common API — la stessa specifica che disciplina Fetch, URL e crypto nei runtime non-browser. Si comportano in modo identico in Node.js 16+, Bun, Deno e Cloudflare Workers.

Gestione di Unicode e caratteri non-ASCII

L'insidia più comune con btoa()è il suo limite stretto di Latin-1. Qualsiasi carattere con un punto di codice superiore a U+00FF causa un'eccezione immediata:

JavaScript
btoa('Müller & Søren') // ❌ Uncaught DOMException: String contains an invalid character
btoa('résumé')         // ❌ 'é' is U+00E9 = 233 — within Latin-1, this one actually works
btoa('田中太郎')         // ❌ Throws — all CJK characters are above U+00FF

L'approccio corretto consiste nel codificare prima la stringa in byte UTF-8, poi codificare quei byte in Base64. JavaScript fornisce TextEncoder esattamente per questo scopo:

Approccio TextEncoder — sicuro per qualsiasi input Unicode

JavaScript (browser + Node.js 16+)
// Utility functions for Unicode-safe Base64
function toBase64(text: string): string {
  const bytes = new TextEncoder().encode(text)
  const chars = Array.from(bytes, byte => String.fromCharCode(byte))
  return btoa(chars.join(''))
}

function fromBase64(encoded: string): string {
  const binary = atob(encoded)
  const bytes  = Uint8Array.from(binary, ch => ch.charCodeAt(0))
  return new TextDecoder().decode(bytes)
}

// Works with any language or script
const orderNote = 'Confermato: Marco Rossi — magazzino Roma, qtà: 250'
const encoded   = toBase64(orderNote)
const decoded   = fromBase64(encoded)

console.log(encoded)
// Q29uZmVybWF0bzogTWFyY28gUm9zc2kg4oCTIG1hZ2F6em5vIFJvbWEsIHF0w6A6IDI1MA==

console.log(decoded === orderNote) // true
Nota:Se sei già in Node.js, salta completamente il workaround TextEncoder — usa Buffer.from(text, 'utf8').toString('base64'). Gestisce Unicode nativamente ed è più veloce per stringhe lunghe.

Buffer.from() in Node.js — Guida completa con esempi

In Node.js, Bufferè l'API idiomatica per tutte le operazioni sui dati binari, incluse le conversioni di codifica. Precede TextEncoder di anni e rimane la scelta preferita per il codice lato server. Vantaggi chiave rispetto a btoa(): supporto nativo di UTF-8, gestione dei dati binari e la scorciatoia di codifica 'base64url' disponibile da Node.js 18.

Codifica e decodifica base del testo

Node.js
// Encoding a server configuration object for storage in an env variable
const dbConfig = JSON.stringify({
  host:           'db-primary.internal',
  port:           5432,
  database:       'analytics_prod',
  maxConnections: 100,
  ssl:            { rejectUnauthorized: true },
})

const encoded = Buffer.from(dbConfig, 'utf8').toString('base64')
console.log(encoded)
// eyJob3N0IjoiZGItcHJpbWFyeS5pbnRlcm5hbCIsInBvcnQiOjU0MzIsImRhdGFiYXNlIjoiYW5h...

// Decoding back
const decoded = Buffer.from(encoded, 'base64').toString('utf8')
const config  = JSON.parse(decoded)

console.log(config.host)           // db-primary.internal
console.log(config.maxConnections) // 100

Codifica di file binari dal disco

Node.js
import { readFileSync, writeFileSync } from 'node:fs'
import { join } from 'node:path'

// Read a TLS certificate and encode it for embedding in a config file
const certPem     = readFileSync(join(process.cwd(), 'ssl', 'server.crt'))
const certBase64  = certPem.toString('base64')

// Store as a single-line string — suitable for env vars or JSON configs
writeFileSync('./dist/cert.b64', certBase64, 'utf8')

console.log(`Certificate encoded: ${certBase64.length} characters`)
// Certificate encoded: 2856 characters

// Restore the binary cert from the encoded value
const restored = Buffer.from(certBase64, 'base64')
console.log(restored.equals(certPem)) // true

Codifica asincrona di file con gestione degli errori

Node.js
import { readFile } from 'node:fs/promises'

async function encodeFileToBase64(filePath: string): Promise<string> {
  try {
    const buffer = await readFile(filePath)
    return buffer.toString('base64')
  } catch (err) {
    const code = (err as NodeJS.ErrnoException).code
    if (code === 'ENOENT') throw new Error(`File not found: ${filePath}`)
    if (code === 'EACCES') throw new Error(`Permission denied: ${filePath}`)
    throw err
  }
}

// Encode a PDF for an email attachment payload
const reportBase64 = await encodeFileToBase64('./reports/q1-financials.pdf')

const emailPayload = {
  to:          'finance-team@company.internal',
  subject:     'Q1 Financial Report',
  attachments: [{
    filename:    'q1-financials.pdf',
    content:     reportBase64,
    encoding:    'base64',
    contentType: 'application/pdf',
  }],
}

console.log(`Attachment: ${reportBase64.length} chars`)

Funzioni Base64 JavaScript — Riferimento parametri

A differenza del modulo base64di Python, JavaScript non ha un'unica funzione Base64 unificata. L'API dipende dall'ambiente di destinazione. Ecco il riferimento completo per tutti gli approcci nativi:

FunzioneTipo di inputUnicodeURL-safeDisponibile in
btoa(string)string (Latin-1)❌ lancia oltre U+00FF❌ sostituzione manualeBrowser, Node 16+, Bun, Deno
atob(string)Base64 string❌ restituisce stringa binaria❌ sostituzione manualeBrowser, Node 16+, Bun, Deno
Buffer.from(src, enc) .toString(enc)string | Buffer | Uint8Array✅ codifica utf8✅ base64url in Node 18+Node.js, Bun
TextEncoder().encode(str) + btoa()string (qualsiasi Unicode)✅ tramite byte UTF-8❌ sostituzione manualeBrowser, Node 16+, Deno
Uint8Array.toBase64() (TC39)Uint8Array✅ binario✅ omitPadding + alphabetChrome 130+, Node 22+

La firma Buffer.from(src, enc).toString(enc) accetta diversi valori di codifica rilevanti per Base64:

"base64"
Base64 standard (RFC 4648 §4). Usa + e / con padding =.
"base64url"
Base64 URL-safe (RFC 4648 §5, Node.js 18+). Usa - e _ senza padding.
"utf8"
Predefinito per sorgenti stringa. Usalo quando la sorgente è testo leggibile dall'uomo.
"binary"
Latin-1 / ISO-8859-1. Usato quando la sorgente è una stringa binaria grezza (es. da atob()).

Base64 URL-safe — Codifica per JWT, URL e nomi file

Il Base64 standard usa + e /, che sono riservati negli URL — + viene decodificato come spazio nelle query string, e / è un separatore di percorso. I JWT, i parametri URL, i nomi file e i valori dei cookie richiedono tutti la variante URL-safe: +-, /_, = finale rimosso.

Browser — sostituzione manuale dei caratteri

JavaScript (browser)
function toBase64Url(text: string): string {
  // For ASCII-safe input (e.g., JSON with only ASCII chars)
  return btoa(text)
    .replace(/+/g, '-')
    .replace(///g, '_')
    .replace(/=/g, '')
}

function fromBase64Url(encoded: string): string {
  // Restore standard Base64 characters and padding before decoding
  const base64  = encoded.replace(/-/g, '+').replace(/_/g, '/')
  const padded  = base64 + '==='.slice(0, (4 - base64.length % 4) % 4)
  return atob(padded)
}

// JWT header — must be URL-safe Base64
const header  = JSON.stringify({ alg: 'HS256', typ: 'JWT' })
const encoded = toBase64Url(header)
console.log(encoded) // eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

const decoded = fromBase64Url(encoded)
console.log(decoded) // {"alg":"HS256","typ":"JWT"}

Node.js 18+ — codifica nativa 'base64url'

Node.js 18+
// Node.js 18 added 'base64url' as a first-class Buffer encoding
const sessionPayload = JSON.stringify({
  userId:     'usr_9f2a1c3e8b4d',
  role:       'editor',
  workspaceId:'ws_3a7f91c2',
  exp:        Math.floor(Date.now() / 1000) + 3600,
})

const encoded = Buffer.from(sessionPayload, 'utf8').toString('base64url')
// No + or / or = characters in the output
// eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2U4YjRkIiwicm9sZSI6ImVkaXRvciIsIndvcmtzcGFjZUlkIjoid3NfM2E3ZjkxYzIiLCJleHAiOjE3MTcyMDM2MDB9

const decoded = Buffer.from(encoded, 'base64url').toString('utf8')
console.log(JSON.parse(decoded).role) // editor

Codifica di file e risposte API in JavaScript

Nel codice di produzione, la codifica Base64 viene applicata più spesso ai file trasmessi e alle risposte di API esterne che forniscono contenuto binario. I pattern differiscono tra browser e Node.js, e i dati binari richiedono particolare attenzione.

Browser — codificare un file da un elemento input

JavaScript (browser)
// Modern approach: File.arrayBuffer() (Chrome 76+, Firefox 69+, Safari 14+)
async function encodeFile(file: File): Promise<string> {
  const buffer = await file.arrayBuffer()
  const bytes  = new Uint8Array(buffer)
  const chars  = Array.from(bytes, b => String.fromCharCode(b))
  return btoa(chars.join(''))
}

const uploadInput = document.getElementById('avatar') as HTMLInputElement

uploadInput.addEventListener('change', async (e) => {
  const file = (e.target as HTMLInputElement).files?.[0]
  if (!file) return

  try {
    const encoded = await encodeFile(file)
    const dataUri = `data:${file.type};base64,${encoded}`

    // Preview the image inline
    const img   = document.getElementById('preview') as HTMLImageElement
    img.src     = dataUri
    img.hidden  = false

    console.log(`Encoded ${file.name} (${file.size} bytes) → ${encoded.length} Base64 chars`)
  } catch (err) {
    console.error('Encoding failed:', err)
  }
})

Recupero di dati binari codificati in Base64 da un'API

JavaScript
// GitHub Contents API returns file content as Base64 with embedded newlines
async function fetchRepoFile(
  owner: string,
  repo:  string,
  path:  string,
  token: string,
): Promise<string> {
  const res = await fetch(
    `https://api.github.com/repos/${owner}/${repo}/contents/${path}`,
    {
      headers: {
        Authorization: `Bearer ${token}`,
        Accept: 'application/vnd.github.v3+json',
      },
    }
  )

  if (!res.ok) throw new Error(`GitHub API ${res.status}: ${res.statusText}`)

  const data = await res.json() as { content: string; encoding: string; size: number }

  if (data.encoding !== 'base64') {
    throw new Error(`Unexpected encoding from GitHub: ${data.encoding}`)
  }

  // GitHub wraps output at 60 chars — strip newlines before decoding
  const clean = data.content.replace(/\n/g, '')
  return atob(clean)
}

const openApiSpec = await fetchRepoFile(
  'acme-corp', 'platform-api', 'openapi.json', process.env.GITHUB_TOKEN!
)
const spec = JSON.parse(openApiSpec)
console.log(`API version: ${spec.info.version}`)

Quando hai solo bisogno di ispezionare una risposta codificata durante il debug delle API senza configurare uno script, incolla il valore Base64 direttamente nel Codificatore Base64 — decodifica anche, con output immediato. Utile per ispezionare risposte dell'API GitHub, payload JWT e firme di webhook.

Codifica Base64 da riga di comando con Node.js e Shell

Per script CI/CD, target Makefile o debug occasionale, raramente hai bisogno di uno script completo. Sia gli strumenti di sistema che i one-liner di Node.js coprono la maggior parte dei casi in modo multipiattaforma.

bash
# ── macOS / Linux system base64 ───────────────────────────────────────
# Standard encoding
echo -n "deploy-bot:sk-prod-a7f2c91e4b3d8" | base64
# ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=

# URL-safe variant (replace chars and strip padding)
echo -n "deploy-bot:sk-prod-a7f2c91e4b3d8" | base64 | tr '+/' '-_' | tr -d '='

# Encode a file inline (macOS: -b 0 removes line wrapping; Linux: --wrap=0)
base64 -b 0 ./config/production.json
# or on Linux:
base64 --wrap=0 ./config/production.json

# Decode
echo "ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=" | base64 --decode

# ── Node.js one-liner — works on Windows too ───────────────────────────
node -e "process.stdout.write(Buffer.from(process.argv[1]).toString('base64'))" "my:secret"
# bXk6c2VjcmV0

# URL-safe from Node.js 18+
node -e "process.stdout.write(Buffer.from(process.argv[1]).toString('base64url'))" "my:secret"
# bXk6c2VjcmV0  (same here since there are no special chars)

# Decode in Node.js
node -e "console.log(Buffer.from(process.argv[1], 'base64').toString())" "ZGVwbG95LWJvdA=="
Nota:Su macOS, base64va a capo nell'output ogni 76 caratteri per impostazione predefinita. Questo interrompe l'analisi a valle. Aggiungi sempre -b 0 (macOS) o --wrap=0(Linux) quando hai bisogno di un risultato su una singola riga — ad esempio, quando scrivi in una variabile d'ambiente o in un campo di configurazione.

Alternativa ad alte prestazioni: js-base64

Le API integrate vanno bene per la maggior parte dei casi d'uso. Il motivo principale per ricorrere a una libreria è la coerenza tra ambienti: se pubblichi un pacchetto che gira sia nel browser che in Node.js, usare Bufferrichiede o il rilevamento dell'ambiente o la configurazione del bundler, mentre btoa() richiede il workaround Unicode. js-base64 (oltre 100 M di download settimanali su npm) gestisce entrambi in modo trasparente.

bash
npm install js-base64
# or
pnpm add js-base64
JavaScript
import { toBase64, fromBase64, toBase64Url, fromBase64Url, isValid } from 'js-base64'

// Standard encoding — Unicode-safe, works in browser and Node.js
const telemetryEvent = JSON.stringify({
  eventId:   'evt_7c3a9f1b2d',
  type:      'checkout_completed',
  currency:  'EUR',
  amount:    14900,
  userId:    'usr_4e2b8d6a5c',
  timestamp: 1717200000,
})

const encoded    = toBase64(telemetryEvent)
const urlEncoded = toBase64Url(telemetryEvent) // No +, /, or = characters

const decoded = fromBase64(encoded)
console.log(JSON.parse(decoded).type) // checkout_completed

// Binary data — pass a Uint8Array as second argument
const pngMagicBytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])
const binaryEncoded = toBase64(pngMagicBytes, true) // true = binary mode

// Validation before decoding
const suspicious = 'not!valid@base64#'
console.log(isValid(suspicious)) // false

Internamente, js-base64 usa Buffernativo quando disponibile e ricade su un'implementazione JS pura nel browser. È 2–3× più veloce dell'approccio TextEncoder+btoa per stringhe Unicode lunghe, e l'API simmetrica (toBase64 / fromBase64) elimina il carico mentale di ricordare in quale direzione vanno btoa e atob.

Codifica di file binari di grandi dimensioni con gli Stream di Node.js

Quando hai bisogno di codificare file più grandi di ~50 MB, caricare l'intero file in memoria con readFileSync() diventa un problema. Gli stream di Node.js ti permettono di elaborare i dati in chunk — ma la codifica Base64 ha un vincolo: devi alimentare il codificatore in multipli di 3 byte per evitare padding errato ai confini dei chunk.

Node.js
import { createReadStream, createWriteStream } from 'node:fs'
import { pipeline } from 'node:stream/promises'

// Stream a large binary file to a Base64-encoded output file
async function streamEncodeToBase64(
  inputPath:  string,
  outputPath: string,
): Promise<void> {
  const readStream  = createReadStream(inputPath, { highWaterMark: 3 * 1024 * 256 }) // 768 KB chunks (multiple of 3)
  const writeStream = createWriteStream(outputPath, { encoding: 'utf8' })

  let buffer = Buffer.alloc(0)

  await pipeline(
    readStream,
    async function* (source) {
      for await (const chunk of source) {
        buffer = Buffer.concat([buffer, chunk as Buffer])

        // Encode in complete 3-byte groups to avoid mid-stream padding
        const remainder = buffer.length % 3
        const safe      = buffer.subarray(0, buffer.length - remainder)
        buffer          = buffer.subarray(buffer.length - remainder)

        if (safe.length > 0) yield safe.toString('base64')
      }
      // Flush remaining bytes (may add 1 or 2 '=' padding chars)
      if (buffer.length > 0) yield buffer.toString('base64')
    },
    writeStream,
  )
}

// Usage: encode a 200 MB video attachment
await streamEncodeToBase64(
  './uploads/product-demo.mp4',
  './dist/product-demo.b64',
)
console.log('Stream encoding complete')
Nota:La dimensione del chunk deve essere un multiplo di 3 byte per evitare il padding spurio = nel mezzo dell'output. L'esempio usa 3 * 1024 * 256 = 786.432 byte (768 KB) — regola highWaterMark in base al tuo budget di memoria. Per i file sotto i 50 MB, readFile() + Buffer.toString('base64') è più semplice e sufficientemente veloce.

Errori comuni

Ho esaminato molte basi di codice JavaScript con codifica Base64, e questi quattro errori compaiono regolarmente — spesso non scoperti finché un carattere non-ASCII o un file binario raggiunge il percorso di codifica in produzione.

Errore 1 — Passare Unicode direttamente a btoa()

Problema: btoa() accetta solo caratteri con punti di codice 0–255. Caratteri come ñ, emoji o ideogrammi CJK causano una DOMException immediata. Soluzione: codifica prima con TextEncoder, o usa Buffer.from(text, 'utf8').toString('base64') in Node.js.

Before · JavaScript
After · JavaScript
// ❌ DOMException: The string to be encoded contains
//    characters outside of the Latin1 range
const username = 'Giulia Ferrari'
const encoded  = btoa(username)  // throws
// ✅ Encode as UTF-8 bytes first
function safeEncode(text: string): string {
  const bytes = new TextEncoder().encode(text)
  const chars = Array.from(bytes, b => String.fromCharCode(b))
  return btoa(chars.join(''))
}
const encoded = safeEncode('Giulia Ferrari')
// R2l1bGlhIEZlcnJhcmk=

Errore 2 — Dimenticare di ripristinare il padding prima di atob()

Problema: Il Base64 URL-safe rimuove il padding =. Passare la stringa senza padding direttamente ad atob()produce output errato o lancia un'eccezione a seconda della lunghezza della stringa. Soluzione: ripristina + e / e riaggiungi la giusta quantità di padding prima di chiamare atob().

Before · JavaScript
After · JavaScript
// ❌ atob() may return wrong data or throw
//    on URL-safe Base64 without padding
const jwtSegment = 'eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2UifQ'
const decoded    = atob(jwtSegment) // Unreliable
// ✅ Restore characters and padding first
function decodeBase64Url(input: string): string {
  const b64 = input.replace(/-/g, '+').replace(/_/g, '/')
  const pad = b64 + '==='.slice(0, (4 - b64.length % 4) % 4)
  return atob(pad)
}
const decoded = decodeBase64Url('eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2UifQ')
// {"userId":"usr_9f2a1c3e"}

Errore 3 — Concatenare chunk codificati invece di buffer grezzi

Problema: Ogni chiamata a btoa() o .toString('base64') aggiunge il proprio padding. Concatenare due stringhe Base64 con padding produce output non valido perché il padding deve stare solo alla fine. Soluzione: concatena i dati grezzi prima della codifica.

Before · JavaScript
After · JavaScript
// ❌ Both parts are padded independently —
//    the combined string is not valid Base64
const part1 = Buffer.from('webhook-secret').toString('base64')
// d2ViaG9vay1zZWNyZXQ=  ← has padding
const part2 = Buffer.from('-v2').toString('base64')
// LXYy            ← correct in isolation
const combined = part1 + part2 // ❌ Invalid — padding in the middle
// ✅ Concatenate raw Buffers before encoding
const combined = Buffer.concat([
  Buffer.from('webhook-secret'),
  Buffer.from('-v2'),
]).toString('base64')
// d2ViaG9vay1zZWNyZXQtdjI= — single valid Base64 string

Errore 4 — Usare response.text() per leggere dati binari API prima della codifica

Problema: response.text() interpreta i byte grezzi come UTF-8 e sostituisce le sequenze di byte non riconosciute con il carattere di sostituzione U+FFFD. Qualsiasi contenuto binario — immagini, PDF, audio — viene silenziosamente corrotto prima di raggiungere btoa(). Soluzione: usa response.arrayBuffer() per ottenere i byte grezzi.

Before · JavaScript
After · JavaScript
// ❌ response.text() corrupts binary data
const res     = await fetch('/api/exports/invoice.pdf')
const text    = await res.text()   // ❌ PDF bytes mangled as UTF-8
const encoded = btoa(text)         // ❌ Corrupted Base64
// ✅ arrayBuffer() preserves raw bytes
const res     = await fetch('/api/exports/invoice.pdf')
const buffer  = await res.arrayBuffer()
const bytes   = new Uint8Array(buffer)
const chars   = Array.from(bytes, b => String.fromCharCode(b))
const encoded = btoa(chars.join('')) // ✅ Valid Base64

Metodi Base64 JavaScript — Confronto rapido

MetodoUnicodeDati binariURL-safeAmbientiRichiede installazione
btoa() / atob()❌ Latin-1❌ workaround necessario❌ sostituzione manualeBrowser, Node 16+, Bun, DenoNo
TextEncoder + btoa()✅ UTF-8✅ tramite Uint8Array❌ sostituzione manualeBrowser, Node 16+, DenoNo
Buffer.from().toString()✅ utf8✅ nativo✅ base64url (Node 18+)Node.js, BunNo
Uint8Array.toBase64() (TC39)✅ binario✅ nativo✅ opzione alphabetChrome 130+, Node 22+No
js-base64✅ sempre✅ Uint8Array✅ integratoUniversalenpm install

Scegli btoa()solo quando l'input è comprovabilmente solo ASCII — digest esadecimali, ID numerici o stringhe Latin-1 pre-validate. Per testo fornito dall'utente in un browser, usa TextEncoder + btoa(). Per tutto il codice lato server Node.js, Buffer è la scelta predefinita giusta. Per le librerie che devono girare in entrambi gli ambienti senza configurazione del bundler, js-base64 elimina tutti i casi limite.

Domande frequenti

Perché btoa() lancia "InvalidCharacterError" sulla mia stringa?
btoa() accetta solo caratteri con punti di codice nell'intervallo 0–255 (Latin-1 / ISO-8859-1). Qualsiasi carattere oltre U+00FF — inclusi la maggior parte del cirillico, dell'arabo, degli ideogrammi CJK e molte emoji — causa una DOMException. La soluzione dipende dall'ambiente: nel browser, codifica prima in byte UTF-8 con TextEncoder, converti ogni byte in un carattere con String.fromCharCode(), poi chiama btoa(). In Node.js, usa Buffer.from(text, 'utf8').toString('base64') che gestisce Unicode nativamente.
btoa() è disponibile in Node.js senza alcun import?
Sì, da Node.js 16.0. Sia btoa() che atob() sono registrate come funzioni globali — nessun import richiesto. Si comportano in modo identico alle loro controparti browser, inclusa la restrizione Latin-1. Per il codice server Node.js, Buffer.from() è ancora preferito a btoa() perché gestisce UTF-8 nativamente, supporta dati binari senza workaround e ha l'opzione di codifica 'base64url' aggiunta in Node.js 18.
Qual è la differenza tra Base64 standard e Base64 URL-safe?
Il Base64 standard (RFC 4648 §4) usa + per il valore 62, / per il valore 63 e = per il padding. Questi caratteri hanno significato speciale negli URL: + viene interpretato come spazio nelle query string, e / è un separatore di percorso. Il Base64 URL-safe (RFC 4648 §5) sostituisce - a + e _ a /, e tipicamente omette il padding = del tutto. I JWT usano Base64 URL-safe per tutti e tre i segmenti. In Node.js 18+, Buffer.from(text).toString('base64url') produce direttamente il formato URL-safe.
Come codifico un'immagine in Base64 per una URI dati CSS in JavaScript?
In un browser: usa file.arrayBuffer() per leggere il binario, converti in Uint8Array, poi chiama btoa(Array.from(bytes, b => String.fromCharCode(b)).join('')). Costruisci la URI dati come 'data:' + file.type + ';base64,' + encoded. In Node.js: const encoded = fs.readFileSync('./image.png').toString('base64') e anteponi il tipo MIME. Per i file SVG spesso puoi saltare Base64 completamente e usare invece una URI dati codificata URL, che è più leggibile e leggermente più piccola.
Posso codificare e decodificare in Base64 senza librerie npm nel browser?
Sì. Per input solo ASCII, btoa() e atob() funzionano direttamente. Per Unicode, la coppia TextEncoder / TextDecoder fornisce il set di strumenti completo — entrambi sono integrati in tutti i browser moderni e Node.js 16+. L'unico caso in cui una libreria aggiunge valore genuino è la coerenza tra ambienti: se scrivi un'utilità che deve funzionare in modo identico sia nel browser che in Node.js senza configurazione del bundler, js-base64 rimuove la logica di rilevamento dell'ambiente.
Come decodifico contenuto Base64 dall'API GitHub?
L'API Contents di GitHub restituisce il contenuto del file come Base64 con caratteri di nuova riga incorporati (l'API va a capo nell'output ogni 60 caratteri). Rimuovili prima di decodificare: const clean = data.content.replace(/\n/g, ''); const text = atob(clean);. In Node.js: const text = Buffer.from(data.content.replace(/\n/g, ''), 'base64').toString('utf8');. GitHub usa sempre Base64 standard (non URL-safe), quindi non è necessaria alcuna sostituzione di + → - o / → _.

Strumenti correlati

Per una codifica o decodifica con un clic senza scrivere codice, incolla la tua stringa o i dati binari direttamente nel Codificatore Base64 — gestisce le modalità standard e URL-safe istantaneamente nel tuo browser.

Disponibile anche in:PythonJava
AC
Alex ChenFront-end & Node.js Developer

Alex is a front-end and Node.js developer with extensive experience building web applications and developer tooling. He is passionate about web standards, browser APIs, and the JavaScript ecosystem. In his spare time he contributes to open-source projects and writes about modern JavaScript patterns, performance optimisation, and everything related to the web platform.

SL
Sophie LaurentRevisore tecnico

Sophie is a full-stack developer focused on TypeScript across the entire stack — from React frontends to Express and Fastify backends. She has a particular interest in type-safe API design, runtime validation, and the patterns that make large JavaScript codebases stay manageable. She writes about TypeScript idioms, Node.js internals, and the ever-evolving JavaScript module ecosystem.