Base64 JavaScript โ€” btoa() dan Buffer

ยทFront-end & Node.js DeveloperยทDitinjau olehSophie LaurentยทDiterbitkan

Gunakan Base64 Encode Online gratis langsung di browser Anda โ€” tidak perlu instalasi.

Coba Base64 Encode Online Online โ†’

Saat Anda menyematkan gambar dalam CSS data URI, meneruskan kredensial di header HTTP Authorization, atau menyimpan sertifikat biner dalam variabel lingkungan, Anda perlu mengodekan data JavaScript dengan Base64 secara andal di browser maupun Node.js. JavaScript menyediakan dua API bawaan yang berbeda:btoa() untuk lingkungan browser (tersedia juga di Node.js 16+) dan Buffer.from() untuk Node.js โ€” masing-masing dengan batasan berbeda seputar Unicode, data biner, dan keamanan URL. Untuk encoding cepat tanpa menulis kode, Base64 Encoder ToolDeck menanganinya langsung di browser. Panduan ini mencakup kedua lingkungan dengan contoh siap produksi: penanganan Unicode, varian URL-safe, encoding file dan respons API, penggunaan CLI, dan empat kesalahan yang terus-menerus menyebabkan bug di codebase nyata.

  • โœ“btoa() tersedia secara native di browser dan global di Node.js 16+, tetapi hanya menerima Latin-1 (code point 0โ€“255) โ€” input Unicode akan melempar DOMException
  • โœ“Buffer.from(text, "utf8").toString("base64") adalah padanannya di Node.js yang menangani Unicode secara native tanpa langkah tambahan
  • โœ“Base64 URL-safe mengganti + โ†’ -, / โ†’ _, dan menghapus padding = โ€” gunakan Buffer.from().toString("base64url") di Node.js 18+ untuk one-liner
  • โœ“Untuk data biner (ArrayBuffer, Uint8Array, file), gunakan Buffer di Node.js atau pendekatan arrayBuffer() + Uint8Array di browser โ€” jangan pernah response.text()
  • โœ“Uint8Array.prototype.toBase64() (TC39 Stage 3) sudah tersedia di Node.js 22+ dan Chrome 130+ dan akan menyatukan kedua lingkungan

Apa itu Encoding Base64?

Base64 mengubah data biner sembarang menjadi string yang dibangun dari 64 karakter ASCII yang dapat dicetak: Aโ€“Z, aโ€“z, 0โ€“9, +, dan /. Setiap 3 byte input dipetakan tepat ke 4 karakter Base64; jika panjang input bukan kelipatan 3, satu atau dua karakter padding = ditambahkan. Output yang dikodekan selalu sekitar 33% lebih besar dari aslinya.

Base64 bukan enkripsi โ€” tidak memberikan kerahasiaan. Siapa pun yang memiliki string yang dikodekan dapat mendekodenya dengan satu pemanggilan fungsi. Tujuannya adalah keamanan transport: banyak protokol dan format penyimpanan dirancang untuk teks ASCII 7-bit dan tidak dapat menangani byte biner sembarang. Base64 menjembatani kesenjangan itu. Kasus penggunaan JavaScript yang umum meliputi data URI untuk menyematkan aset, header HTTP Basic Auth, segmen token JWT, lampiran email MIME, dan menyimpan blob biner di JSON API.

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

btoa() โ€” Fungsi Encoding Native Browser

btoa() (binary-to-ASCII) telah tersedia di browser sejak IE10 dan menjadi global di Node.js 16.0 sebagai bagian dari inisiatif kompatibilitas WinterCG. Ini juga bekerja secara native di Deno, Bun, dan Cloudflare Workers. Tidak diperlukan import.

Fungsi ini mengambil satu argumen string dan mengembalikan bentuk yang dikodekan Base64. Padanannya yang simetris atob() (ASCII-to-binary) mendekodenya kembali. Keduanya sinkron dan berjalan dalam memori konstan relatif terhadap ukuran input.

Contoh minimal yang berfungsi

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=

Mendekode dengan 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
Catatan:btoa() dan atob() adalah bagian dari WinterCG Minimum Common API โ€” spesifikasi yang sama yang mengatur Fetch, URL, dan crypto di runtime non-browser. Keduanya berperilaku identik di Node.js 16+, Bun, Deno, dan Cloudflare Workers.

Menangani Unicode dan Karakter Non-ASCII

Jebakan paling umum dari btoa() adalah batas Latin-1 yang ketat. Karakter apa pun dengan code point di atas U+00FF menyebabkan pengecualian langsung:

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

Pendekatan yang benar adalah mengodekan string ke byte UTF-8 terlebih dahulu, kemudian mengodekan byte tersebut dengan Base64. JavaScript menyediakan TextEncoder untuk tujuan ini:

Pendekatan TextEncoder โ€” aman untuk input Unicode apa pun

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 = 'Konfirmasi: Budi Santoso โ€” gudang Jakarta, qty: 250'
const encoded   = toBase64(orderNote)
const decoded   = fromBase64(encoded)

console.log(encoded)
// S29uZmlybWFzaTogQnVkaSBTYW50b3NvIOKAkyBndWRhbmcgSmFrYXJ0YSwgcXR5OiAyNTA=

console.log(decoded === orderNote) // true
Catatan:Jika Anda sudah di Node.js, lewati solusi TextEncoder sepenuhnya โ€” gunakan Buffer.from(text, 'utf8').toString('base64'). Cara ini menangani Unicode secara native dan lebih cepat untuk string besar.

Buffer.from() di Node.js โ€” Panduan Lengkap dengan Contoh

Di Node.js, Buffer adalah API idiomatik untuk semua operasi data biner, termasuk konversi encoding. API ini mendahului TextEncoder bertahun-tahun dan tetap menjadi pilihan utama untuk kode sisi server. Keunggulan utama dibanding btoa(): dukungan UTF-8 native, penanganan data biner, dan pintasan encoding 'base64url' yang tersedia sejak Node.js 18.

Encoding dan decoding teks dasar

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

Encoding file biner dari disk

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

Encoding file async dengan penanganan error

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

Fungsi Base64 JavaScript โ€” Referensi Parameter

Tidak seperti modul base64 Python, JavaScript tidak memiliki satu fungsi Base64 yang terpadu. API-nya bergantung pada lingkungan target. Berikut referensi lengkap untuk semua pendekatan native:

FungsiTipe inputUnicodeURL-safeTersedia di
btoa(string)string (Latin-1)โŒ melempar di atas U+00FFโŒ penggantian manualBrowser, Node 16+, Bun, Deno
atob(string)Base64 stringโŒ mengembalikan string binerโŒ penggantian manualBrowser, Node 16+, Bun, Deno
Buffer.from(src, enc) .toString(enc)string | Buffer | Uint8Arrayโœ… encoding utf8โœ… base64url di Node 18+Node.js, Bun
TextEncoder().encode(str) + btoa()string (Unicode apa pun)โœ… via byte UTF-8โŒ penggantian manualBrowser, Node 16+, Deno
Uint8Array.toBase64() (TC39)Uint8Arrayโœ… binerโœ… omitPadding + alphabetChrome 130+, Node 22+

Tanda tangan Buffer.from(src, enc).toString(enc) menerima beberapa nilai encoding yang relevan dengan Base64:

"base64"
Base64 standar (RFC 4648 ยง4). Menggunakan + dan / dengan padding =.
"base64url"
Base64 URL-safe (RFC 4648 ยง5, Node.js 18+). Menggunakan - dan _ tanpa padding.
"utf8"
Default untuk sumber string. Gunakan ketika sumbernya adalah teks yang dapat dibaca manusia.
"binary"
Latin-1 / ISO-8859-1. Digunakan ketika sumbernya adalah string biner mentah (mis., dari atob()).

Base64 URL-safe โ€” Encoding untuk JWT, URL, dan Nama File

Base64 standar menggunakan + dan /, yang merupakan karakter khusus di URL โ€” + didekode sebagai spasi di query string, dan / adalah pemisah path. JWT, parameter URL, nama file, dan nilai cookie semuanya memerlukan varian URL-safe: + โ†’ -, / โ†’ _, trailing = dihapus.

Browser โ€” penggantian karakter manual

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+ โ€” encoding 'base64url' native

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

Encoding File dan Respons API di JavaScript

Dalam kode produksi, encoding Base64 paling sering diterapkan pada file yang sedang dikirim dan pada respons dari API eksternal yang mengirimkan konten biner. Polanya berbeda antara browser dan Node.js, dan data biner memerlukan perhatian khusus.

Browser โ€” encode file dari elemen 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)
  }
})

Mengambil data biner Base64 dari 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}`)

Ketika Anda hanya perlu memeriksa respons yang dikodekan saat debugging API tanpa menyiapkan skrip, tempel nilai Base64 langsung ke Base64 Encoder โ€” tool ini juga mendekode, dengan output langsung. Berguna untuk memeriksa respons GitHub API, payload JWT, dan tanda tangan webhook.

Encoding Base64 dari Command-Line di Node.js dan Shell

Untuk skrip CI/CD, target Makefile, atau debugging sekali pakai, Anda jarang memerlukan skrip lengkap. Alat sistem maupun one-liner Node.js mencakup sebagian besar kasus lintas platform.

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=="
Catatan:Di macOS, base64 membungkus output pada 76 karakter secara default. Ini merusak parsing downstream. Selalu tambahkan -b 0 (macOS) atau --wrap=0 (Linux) ketika Anda memerlukan hasil satu baris โ€” misalnya, saat menulis ke variabel lingkungan atau field konfigurasi.

Alternatif Berperforma Tinggi: js-base64

API bawaan sudah cukup untuk sebagian besar kasus penggunaan. Alasan utama untuk menggunakan library adalah konsistensi lintas lingkungan: jika Anda mengirimkan paket yang berjalan di browser maupun Node.js, menggunakan Buffer memerlukan deteksi lingkungan atau konfigurasi bundler, sementara btoa() memerlukan solusi Unicode. js-base64 (100M+ unduhan mingguan npm) menangani keduanya secara transparan.

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

Di balik layar, js-base64 menggunakan Buffer native jika tersedia dan jatuh kembali ke implementasi pure-JS di browser. Kecepatannya 2โ€“3ร— lebih cepat dari pendekatan TextEncoder+btoa untuk string Unicode besar, dan API simetrisnya ( toBase64 / fromBase64) menghilangkan beban mental untuk mengingat arah btoa dan atob.

Encoding File Biner Besar dengan Node.js Streams

Ketika Anda perlu mengodekan file yang lebih besar dari ~50 MB, memuat seluruh file ke memori dengan readFileSync() menjadi masalah. Stream Node.js memungkinkan Anda memproses data dalam potongan โ€” tetapi encoding Base64 memiliki batasan: Anda harus memberi makan encoder dalam kelipatan 3 byte untuk menghindari padding yang salah di batas potongan.

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')
Catatan:Ukuran potongan harus kelipatan 3 byte untuk menghindari padding = yang tidak perlu di tengah output. Contoh ini menggunakan 3 * 1024 * 256 = 786.432 byte (768 KB) โ€” sesuaikan highWaterMark berdasarkan anggaran memori Anda. Untuk file di bawah 50 MB, readFile() + Buffer.toString('base64') lebih sederhana dan cukup cepat.

Kesalahan Umum

Saya telah meninjau banyak codebase JavaScript dengan encoding Base64, dan keempat kesalahan ini muncul secara konsisten โ€” sering tidak ditemukan sampai karakter non-ASCII atau file biner mencapai jalur encoding di produksi.

Kesalahan 1 โ€” Meneruskan Unicode langsung ke btoa()

Masalah: btoa() hanya menerima karakter dengan code point 0โ€“255. Karakter seperti รฑ, emoji, atau ideograf CJK menyebabkan DOMException langsung. Solusi: encode dengan TextEncoder terlebih dahulu, atau gunakan Buffer.from(text, 'utf8').toString('base64') di Node.js.

Before ยท JavaScript
After ยท JavaScript
// โŒ DOMException: The string to be encoded contains
//    characters outside of the Latin1 range
const username = 'Dewi Rahayu'
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('Dewi Rahayu')
// RGV3aSBSYWhheXU=

Kesalahan 2 โ€” Lupa memulihkan padding sebelum atob()

Masalah: Base64 URL-safe menghapus padding =. Meneruskan string tanpa padding langsung ke atob() menghasilkan output yang salah atau melempar tergantung pada panjang string. Solusi: pulihkan + dan / dan tambahkan kembali jumlah padding yang tepat sebelum memanggil 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"}

Kesalahan 3 โ€” Menggabungkan potongan yang sudah dikodekan alih-alih buffer mentah

Masalah: Setiap panggilan ke btoa() atau .toString('base64') menambahkan paddingnya sendiri. Menggabungkan dua string Base64 yang sudah dipadding menghasilkan output yang tidak valid karena padding hanya boleh ada di akhir. Solusi: gabungkan data mentah sebelum encoding.

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

Kesalahan 4 โ€” Menggunakan response.text() untuk membaca data API biner sebelum encoding

Masalah: response.text() menginterpretasikan byte mentah sebagai UTF-8 dan mengganti urutan byte yang tidak dikenali dengan karakter pengganti U+FFFD. Konten biner apa pun โ€” gambar, PDF, audio โ€” rusak diam-diam sebelum mencapai btoa(). Solusi: gunakan response.arrayBuffer() untuk mendapatkan byte mentah.

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

Metode Base64 JavaScript โ€” Perbandingan Cepat

MetodeUnicodeData binerURL-safeLingkunganPerlu install
btoa() / atob()โŒ Latin-1โŒ perlu solusiโŒ penggantian manualBrowser, Node 16+, Bun, DenoTidak
TextEncoder + btoa()โœ… UTF-8โœ… via Uint8ArrayโŒ penggantian manualBrowser, Node 16+, DenoTidak
Buffer.from().toString()โœ… utf8โœ… nativeโœ… base64url (Node 18+)Node.js, BunTidak
Uint8Array.toBase64() (TC39)โœ… binerโœ… nativeโœ… opsi alphabetChrome 130+, Node 22+Tidak
js-base64โœ… selaluโœ… Uint8Arrayโœ… bawaanUniversalnpm install

Pilih btoa() hanya ketika input terbukti hanya ASCII โ€” hex digest, ID numerik, atau string Latin-1 yang sudah divalidasi. Untuk teks yang diberikan pengguna di browser, gunakan TextEncoder + btoa(). Untuk semua kode Node.js sisi server, Buffer adalah default yang tepat. Untuk library yang perlu berjalan di kedua lingkungan tanpa konfigurasi bundler, js-base64 menghilangkan semua edge case.

Pertanyaan yang Sering Diajukan

Mengapa btoa() melempar "InvalidCharacterError" pada string saya?
btoa() hanya menerima karakter dengan code point dalam rentang 0โ€“255 (Latin-1 / ISO-8859-1). Karakter apa pun di atas U+00FF โ€” termasuk sebagian besar Sirilik, Arab, ideograf CJK, dan banyak emoji โ€” menyebabkan DOMException. Solusinya bergantung pada lingkungan Anda: di browser, encode ke byte UTF-8 dengan TextEncoder terlebih dahulu, konversi setiap byte ke karakter dengan String.fromCharCode(), lalu panggil btoa(). Di Node.js, gunakan Buffer.from(text, 'utf8').toString('base64') yang menangani Unicode secara native.
Apakah btoa() tersedia di Node.js tanpa import apa pun?
Ya, sejak Node.js 16.0. Baik btoa() maupun atob() terdaftar sebagai fungsi global โ€” tidak diperlukan import. Keduanya berperilaku identik dengan padanannya di browser, termasuk batasan Latin-1. Untuk kode server Node.js, Buffer.from() masih lebih disukai daripada btoa() karena menangani UTF-8 secara native, mendukung data biner tanpa solusi alternatif, dan memiliki opsi encoding 'base64url' yang ditambahkan di Node.js 18.
Apa perbedaan antara Base64 standar dan Base64 URL-safe?
Base64 standar (RFC 4648 ยง4) menggunakan + untuk nilai 62, / untuk nilai 63, dan = untuk padding. Karakter-karakter ini memiliki makna khusus di URL: + diinterpretasikan sebagai spasi di query string, dan / adalah pemisah path. Base64 URL-safe (RFC 4648 ยง5) mengganti - dengan + dan _ dengan /, dan biasanya menghilangkan padding = sepenuhnya. JWT menggunakan Base64 URL-safe untuk ketiga segmennya. Di Node.js 18+, Buffer.from(text).toString('base64url') menghasilkan format URL-safe secara langsung.
Bagaimana cara mengodekan gambar ke Base64 untuk CSS data URI di JavaScript?
Di browser: gunakan file.arrayBuffer() untuk membaca biner, konversi ke Uint8Array, lalu panggil btoa(Array.from(bytes, b => String.fromCharCode(b)).join('')). Bangun data URI sebagai 'data:' + file.type + ';base64,' + encoded. Di Node.js: const encoded = fs.readFileSync('./image.png').toString('base64') dan tambahkan tipe MIME di depan. Untuk file SVG, Anda sering bisa melewati Base64 sepenuhnya dan menggunakan data URI yang di-URL-encode, yang lebih mudah dibaca dan sedikit lebih kecil.
Bisakah saya mengodekan dan mendekode Base64 tanpa library npm di browser?
Ya. Untuk input hanya ASCII, btoa() dan atob() bekerja langsung. Untuk Unicode, pasangan TextEncoder / TextDecoder memberikan Anda toolset yang lengkap โ€” keduanya sudah terpasang di semua browser modern dan Node.js 16+. Satu-satunya kasus di mana library benar-benar menambah nilai adalah konsistensi lintas lingkungan: jika Anda menulis utilitas yang harus bekerja identik di browser maupun Node.js tanpa konfigurasi bundler, js-base64 menghilangkan logika deteksi lingkungan.
Bagaimana cara mendekode konten Base64 dari GitHub API?
GitHub Contents API mengembalikan konten file sebagai Base64 dengan karakter newline yang disematkan (API membungkus output pada 60 karakter). Hapus sebelum mendekode: const clean = data.content.replace(/\n/g, ''); const text = atob(clean);. Di Node.js: const text = Buffer.from(data.content.replace(/\n/g, ''), 'base64').toString('utf8');. GitHub selalu menggunakan Base64 standar (bukan URL-safe), jadi tidak diperlukan substitusi + โ†’ - atau / โ†’ _.

Alat Terkait

Untuk encode atau decode satu klik tanpa menulis kode apa pun, tempel string atau biner Anda langsung ke Base64 Encoder โ€” menangani mode standar dan URL-safe langsung di browser Anda.

Tersedia juga dalam: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 LaurentPeninjau teknis

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.