Base64 w JavaScript — btoa() i Buffer

·Front-end & Node.js Developer·Sprawdzono przezSophie Laurent·Opublikowano

Użyj darmowego Koder Base64 Online bezpośrednio w przeglądarce — bez instalacji.

Wypróbuj Koder Base64 Online online →

Kiedy osadzasz obraz w CSS data URI, przekazujesz poświadczenia w nagłówku HTTP Authorization lub przechowujesz binarny certyfikat w zmiennej środowiskowej, musisz niezawodnie kodować dane JavaScript w Base64 zarówno w przeglądarce, jak i Node.js. JavaScript udostępnia dwa odrębne wbudowane API:btoa() dla środowisk przeglądarkowych (dostępne też w Node.js 16+) oraz Buffer.from() dla Node.js — każde z różnymi ograniczeniami dotyczącymi Unicode, danych binarnych i bezpieczeństwa URL. Aby szybko zakodować dane bez pisania kodu, ToolDeck's Base64 Encoder obsługuje to natychmiast w przeglądarce. Ten przewodnik obejmuje oba środowiska z przykładami gotowymi do produkcji: obsługa Unicode, warianty URL-bezpieczne, kodowanie plików i odpowiedzi API, użycie CLI i cztery błędy, które konsekwentnie powodują problemy w rzeczywistych bazach kodu.

  • btoa() jest wbudowane w przeglądarkę i dostępne globalnie w Node.js 16+, ale akceptuje tylko Latin-1 (punkty kodowe 0–255) — wejście Unicode rzuca DOMException
  • Buffer.from(text, "utf8").toString("base64") to odpowiednik Node.js, który natywnie obsługuje Unicode bez dodatkowych kroków
  • URL-bezpieczny Base64 zastępuje + na -, / na _ i usuwa padding = — w Node.js 18+ użyj Buffer.from().toString("base64url") jako jednolinijkowe rozwiązanie
  • Dla danych binarnych (ArrayBuffer, Uint8Array, pliki) użyj Buffer w Node.js lub podejścia arrayBuffer() + Uint8Array w przeglądarce — nigdy response.text()
  • Uint8Array.prototype.toBase64() (TC39 Stage 3) jest już dostępne w Node.js 22+ i Chrome 130+ i ujednolici oba środowiska

Czym jest kodowanie Base64?

Base64 konwertuje dowolne dane binarne na ciąg znaków zbudowany z 64 drukowalnych znaków ASCII: A–Z, a–z, 0–9, + i /. Każde 3 bajty wejścia mapują się dokładnie na 4 znaki Base64; jeśli długość wejścia nie jest wielokrotnością 3, dodawane są jeden lub dwa znaki wypełnienia =. Zakodowane wyjście jest zawsze o około 33% większe niż oryginał.

Base64 to nie szyfrowanie — nie zapewnia poufności. Każdy, kto posiada zakodowany ciąg, może go zdekodować jednym wywołaniem funkcji. Jego celem jest bezpieczeństwo transportu: wiele protokołów i formatów przechowywania zostało zaprojektowanych dla 7-bitowego tekstu ASCII i nie może obsługiwać dowolnych bajtów binarnych. Base64 wypełnia tę lukę. Typowe przypadki użycia JavaScript obejmują data URI do wstawiania zasobów, nagłówki HTTP Basic Auth, segmenty tokenów JWT, załączniki MIME w e-mailach i przechowywanie binarnych obiektów blob w API JSON.

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

btoa() — natywna funkcja kodowania przeglądarki

btoa() (binary-to-ASCII) jest dostępna w przeglądarkach od IE10 i stała się globalną funkcją w Node.js 16.0 jako część inicjatywy zgodności WinterCG. Działa też natywnie w Deno, Bun i Cloudflare Workers. Nie wymaga importu.

Funkcja przyjmuje jeden argument łańcuchowy i zwraca jego zakodowaną formę Base64. Symetryczny odpowiednik atob() (ASCII-to-binary) dekoduje z powrotem. Obie są synchroniczne i działają przy stałej pamięci względem rozmiaru wejścia.

Minimalny działający przykład

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=

Dekodowanie za pomocą 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
Uwaga:btoa() i atob() są częścią WinterCG Minimum Common API — tej samej specyfikacji, która reguluje Fetch, URL i crypto w środowiskach innych niż przeglądarka. Zachowują się identycznie w Node.js 16+, Bun, Deno i Cloudflare Workers.

Obsługa Unicode i znaków spoza ASCII

Najczęstszą pułapką btoa() jest jej ścisła granica Latin-1. Każdy znak z punktem kodowym powyżej U+00FF powoduje natychmiastowy wyjątek:

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

Prawidłowe podejście to zakodowanie ciągu do bajtów UTF-8 najpierw, a następnie zakodowanie tych bajtów w Base64. JavaScript dostarcza TextEncoder dokładnie do tego celu:

Podejście TextEncoder — bezpieczne dla dowolnego wejścia 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 = 'Potwierdzono: Piotr Kowalski — magazyn Warszawa, ilość: 250'
const encoded   = toBase64(orderNote)
const decoded   = fromBase64(encoded)

console.log(encoded)
// UG90d2llcmR6b25vOiBQaW90ciBLb3dhbHNraSDigJQgbWFnYXp5biBXYXJzemF3YSwgaWzDn8WTxIc6IDI1MA==

console.log(decoded === orderNote) // true
Uwaga:Jeśli już pracujesz w Node.js, pomiń całkowicie obejście TextEncoder — użyj Buffer.from(text, 'utf8').toString('base64'). Obsługuje Unicode natywnie i jest szybszy dla dużych ciągów.

Buffer.from() w Node.js — kompletny przewodnik z przykładami

W Node.js Buffer jest idiomatycznym API dla wszystkich operacji na danych binarnych, w tym konwersji kodowania. Poprzedza TextEncoder o lata i pozostaje preferowanym wyborem dla kodu po stronie serwera. Kluczowe zalety nad btoa(): natywna obsługa UTF-8, obsługa danych binarnych i skrót kodowania 'base64url' dostępny od Node.js 18.

Podstawowe kodowanie i dekodowanie tekstu

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

Kodowanie plików binarnych z dysku

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

Asynchroniczne kodowanie pliku z obsługą błędów

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`)

Funkcje Base64 JavaScript — dokumentacja parametrów

W przeciwieństwie do modułu base64 Pythona, JavaScript nie ma jednej zunifikowanej funkcji Base64. API zależy od środowiska docelowego. Oto kompletna dokumentacja dla wszystkich natywnych podejść:

FunkcjaTyp wejściaUnicodeURL-bezpiecznyDostępny w
btoa(string)string (Latin-1)❌ rzuca powyżej U+00FF❌ ręczne zastępowanieBrowser, Node 16+, Bun, Deno
atob(string)Base64 string❌ zwraca ciąg binarny❌ ręczne zastępowanieBrowser, Node 16+, Bun, Deno
Buffer.from(src, enc) .toString(enc)string | Buffer | Uint8Array✅ kodowanie utf8✅ base64url w Node 18+Node.js, Bun
TextEncoder().encode(str) + btoa()string (dowolny Unicode)✅ przez bajty UTF-8❌ ręczne zastępowanieBrowser, Node 16+, Deno
Uint8Array.toBase64() (TC39)Uint8Array✅ binarny✅ omitPadding + alphabetChrome 130+, Node 22+

Sygnatura Buffer.from(src, enc).toString(enc) akceptuje kilka wartości kodowania istotnych dla Base64:

"base64"
Standardowy Base64 (RFC 4648 §4). Używa + i / z paddingiem =.
"base64url"
URL-bezpieczny Base64 (RFC 4648 §5, Node.js 18+). Używa - i _ bez paddingu.
"utf8"
Domyślne dla źródeł tekstowych. Użyj gdy źródłem jest tekst czytelny dla człowieka.
"binary"
Latin-1 / ISO-8859-1. Używane gdy źródłem jest surowy ciąg binarny (np. z atob()).

URL-bezpieczny Base64 — kodowanie dla JWT, URL i nazw plików

Standardowy Base64 używa + i /, które są zarezerwowane w URL — + jest dekodowany jako spacja w ciągach zapytań, a / jest separatorem ścieżek. JWT, parametry URL, nazwy plików i wartości cookie wymagają wariantu URL-bezpiecznego: +-, /_, usunięcie końcowego =.

Przeglądarka — ręczne zastępowanie znaków

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+ — natywne kodowanie '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

Kodowanie plików i odpowiedzi API w JavaScript

W kodzie produkcyjnym kodowanie Base64 jest najczęściej stosowane do przesyłanych plików i odpowiedzi z zewnętrznych API dostarczających zawartość binarną. Wzorce różnią się między przeglądarką a Node.js, a dane binarne wymagają szczególnej uwagi.

Przeglądarka — kodowanie pliku z elementu 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)
  }
})

Pobieranie binarnych danych zakodowanych w Base64 z 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}`)

Kiedy podczas debugowania API chcesz sprawdzić zakodowaną odpowiedź bez pisania skryptu, wklej wartość Base64 bezpośrednio do Base64 Encoder — obsługuje też dekodowanie z natychmiastowym wynikiem. Przydatne do sprawdzania odpowiedzi GitHub API, ładunków JWT i podpisów webhook.

Kodowanie Base64 w wierszu poleceń w Node.js i powłoce

Do skryptów CI/CD, celów Makefile lub jednorazowego debugowania rzadko potrzebujesz pełnego skryptu. Zarówno narzędzia systemowe, jak i jednolinijkowce Node.js pokrywają większość przypadków na różnych platformach.

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=="
Uwaga:Na macOS base64 domyślnie zawija wyjście po 76 znakach. Powoduje to błędy w dalszym parsowaniu. Zawsze dodawaj -b 0 (macOS) lub --wrap=0 (Linux), gdy potrzebujesz wyniku w jednej linii — na przykład przy zapisywaniu do zmiennej środowiskowej lub pola konfiguracyjnego.

Wysokowydajna alternatywa: js-base64

Wbudowane API są wystarczające dla większości przypadków. Głównym powodem sięgania po bibliotekę jest spójność między środowiskami: jeśli publikujesz pakiet działający zarówno w przeglądarce, jak i Node.js, użycie Buffer wymaga wykrywania środowiska lub konfiguracji bundlera, podczas gdy btoa() wymaga obejścia Unicode. js-base64 (ponad 100M tygodniowych pobrań z npm) obsługuje oba transparentnie.

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

Pod spodem js-base64 używa natywnego Buffer, gdy jest dostępny, i wraca do czystej implementacji JS w przeglądarce. Jest 2–3× szybszy niż podejście TextEncoder+btoa dla dużych ciągów Unicode, a symetryczne API (toBase64 / fromBase64) eliminuje konieczność pamiętania kierunku btoa i atob.

Kodowanie dużych plików binarnych przy użyciu strumieni Node.js

Gdy musisz kodować pliki większe niż ~50 MB, ładowanie całego pliku do pamięci za pomocą readFileSync() staje się problemem. Strumienie Node.js pozwalają przetwarzać dane w kawałkach — ale kodowanie Base64 ma ograniczenie: musisz podawać enkoderu wielokrotności 3 bajtów, aby uniknąć nieprawidłowego paddingu na granicach kawałków.

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')
Uwaga:Rozmiar kawałka musi być wielokrotnością 3 bajtów, aby uniknąć zbędnego paddingu = w środku wyjścia. Przykład używa 3 * 1024 * 256 = 786 432 bajtów (768 KB) — dostosuj highWaterMark zależnie od budżetu pamięci. Dla plików poniżej 50 MB, readFile() + Buffer.toString('base64') jest prostsze i wystarczająco szybkie.

Typowe błędy

Przejrzałem wiele baz kodu JavaScript z kodowaniem Base64 i te cztery błędy pojawiają się konsekwentnie — często nieodkryte aż do momentu, gdy znak spoza ASCII lub plik binarny trafi na ścieżkę kodowania w produkcji.

Błąd 1 — Przekazanie Unicode bezpośrednio do btoa()

Problem: btoa() akceptuje tylko znaki z punktami kodowymi 0–255. Znaki takie jak ñ, emoji lub ideografy CJK powodują natychmiastowy DOMException. Rozwiązanie: zakoduj najpierw za pomocą TextEncoder lub użyj Buffer.from(text, 'utf8').toString('base64') w Node.js.

Before · JavaScript
After · JavaScript
// ❌ DOMException: The string to be encoded contains
//    characters outside of the Latin1 range
const username = 'Алексей Иванов'
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('Алексей Иванов')
// 0JDQu9C10LrRgdC10Lkg0JjQstCw0L3QvtCy

Błąd 2 — Zapomnienie o przywróceniu paddingu przed atob()

Problem: URL-bezpieczny Base64 usuwa padding =. Przekazanie ciągu bez paddingu bezpośrednio do atob() daje nieprawidłowe wyjście lub rzuca wyjątek w zależności od długości ciągu. Rozwiązanie: przywróć + i / i dodaj właściwą ilość paddingu przed wywołaniem 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"}

Błąd 3 — Łączenie zakodowanych kawałków zamiast surowych buforów

Problem: Każde wywołanie btoa() lub .toString('base64') dodaje własny padding. Łączenie dwóch ciągów Base64 z paddingiem daje nieprawidłowe wyjście, ponieważ padding należy tylko na samym końcu. Rozwiązanie: połącz surowe dane przed kodowaniem.

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

Błąd 4 — Użycie response.text() do odczytu binarnych danych API przed kodowaniem

Problem: response.text() interpretuje surowe bajty jako UTF-8 i zastępuje nierozpoznane sekwencje bajtów znakiem zastępczym U+FFFD. Dowolna zawartość binarna — obrazy, PDF-y, audio — jest po cichu uszkadzana zanim dotrze do btoa(). Rozwiązanie: użyj response.arrayBuffer() aby uzyskać surowe bajty.

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

Metody Base64 JavaScript — szybkie porównanie

MetodaUnicodeDane binarneURL-bezpiecznyŚrodowiskaWymaga instalacji
btoa() / atob()❌ Latin-1❌ obejście wymagane❌ ręczne zastępowanieBrowser, Node 16+, Bun, DenoNie
TextEncoder + btoa()✅ UTF-8✅ przez Uint8Array❌ ręczne zastępowanieBrowser, Node 16+, DenoNie
Buffer.from().toString()✅ utf8✅ natywne✅ base64url (Node 18+)Node.js, BunNie
Uint8Array.toBase64() (TC39)✅ binarne✅ natywne✅ opcja alphabetChrome 130+, Node 22+Nie
js-base64✅ zawsze✅ Uint8Array✅ wbudowaneUniwersalnenpm install

Wybierz btoa() tylko wtedy, gdy wejście jest potwierdzenie wyłącznie ASCII — skróty szesnastkowe, identyfikatory numeryczne lub wcześniej zweryfikowane ciągi Latin-1. Dla tekstu dostarczonego przez użytkownika w przeglądarce używaj TextEncoder + btoa(). Dla całego kodu po stronie serwera Node.js Buffer jest właściwym domyślnym wyborem. Dla bibliotek, które muszą działać w obu środowiskach bez konfiguracji bundlera, js-base64 eliminuje wszystkie przypadki brzegowe.

Często zadawane pytania

Dlaczego btoa() rzuca "InvalidCharacterError" na moim ciągu?
btoa() akceptuje tylko znaki z punktami kodowymi w zakresie 0–255 (Latin-1 / ISO-8859-1). Każdy znak powyżej U+00FF — w tym większość cyrylicy, arabskiego, ideogramów CJK i wielu emoji — powoduje DOMException. Sposób naprawy zależy od środowiska: w przeglądarce zakoduj do bajtów UTF-8 za pomocą TextEncoder, zamień każdy bajt na znak z String.fromCharCode(), następnie wywołaj btoa(). W Node.js użyj Buffer.from(text, 'utf8').toString('base64'), który obsługuje Unicode natywnie.
Czy btoa() jest dostępne w Node.js bez żadnego importu?
Tak, od Node.js 16.0. Zarówno btoa() jak i atob() są zarejestrowane jako funkcje globalne — import nie jest wymagany. Zachowują się identycznie jak ich odpowiedniki przeglądarkowe, włącznie z ograniczeniem Latin-1. W kodzie serwera Node.js Buffer.from() jest nadal preferowany nad btoa(), ponieważ obsługuje UTF-8 natywnie, obsługuje dane binarne bez obejść i ma opcję kodowania 'base64url' dodaną w Node.js 18.
Jaka jest różnica między standardowym Base64 a URL-bezpiecznym Base64?
Standardowy Base64 (RFC 4648 §4) używa + dla wartości 62, / dla wartości 63 i = dla paddingu. Te znaki mają specjalne znaczenie w URL: + jest interpretowany jako spacja w ciągach zapytań, a / jest separatorem ścieżek. URL-bezpieczny Base64 (RFC 4648 §5) zastępuje + przez - i / przez _, i zazwyczaj całkowicie pomija padding =. JWT używa URL-bezpiecznego Base64 dla wszystkich trzech segmentów. W Node.js 18+ Buffer.from(text).toString('base64url') bezpośrednio generuje format URL-bezpieczny.
Jak zakodować obraz do Base64 dla CSS data URI w JavaScript?
W przeglądarce: użyj file.arrayBuffer() do odczytu danych binarnych, zamień na Uint8Array, następnie wywołaj btoa(Array.from(bytes, b => String.fromCharCode(b)).join('')). Zbuduj data URI jako 'data:' + file.type + ';base64,' + encoded. W Node.js: const encoded = fs.readFileSync('./image.png').toString('base64') i dodaj typ MIME na początku. Dla plików SVG możesz często całkowicie pominąć Base64 i użyć URL-kodowanego data URI, który jest bardziej czytelny i nieco mniejszy.
Czy mogę kodować i dekodować Base64 bez biblioteki npm w przeglądarce?
Tak. Dla wejścia wyłącznie ASCII, btoa() i atob() działają bezpośrednio. Dla Unicode, para TextEncoder / TextDecoder daje pełen zestaw narzędzi — oba są wbudowane we wszystkie nowoczesne przeglądarki i Node.js 16+. Jedynym przypadkiem, gdy biblioteka naprawdę dodaje wartość, jest spójność między środowiskami: jeśli piszesz narzędzie, które musi działać identycznie zarówno w przeglądarce, jak i Node.js bez konfiguracji bundlera, js-base64 usuwa logikę wykrywania środowiska.
Jak zdekodować zawartość Base64 z GitHub API?
GitHub Contents API zwraca zawartość pliku jako Base64 z wbudowanymi znakami nowej linii (API zawija wyjście po 60 znakach). Usuń je przed dekodowaniem: const clean = data.content.replace(/\n/g, ''); const text = atob(clean);. W Node.js: const text = Buffer.from(data.content.replace(/\n/g, ''), 'base64').toString('utf8');. GitHub zawsze używa standardowego Base64 (nie URL-bezpiecznego), więc podstawianie + → - lub / → _ nie jest potrzebne.

Powiązane narzędzia

Aby jednym kliknięciem zakodować lub zdekodować bez pisania kodu, wklej ciąg lub dane binarne bezpośrednio do Base64 Encoder — obsługuje tryb standardowy i URL-bezpieczny natychmiast w przeglądarce.

Dostępne również w: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 LaurentRecenzent techniczny

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.