ToolDeck

Decode Base64 ใน JavaScript: atob() และ Buffer

·Front-end & Node.js Developer·ตรวจสอบโดยSophie Laurent·เผยแพร่เมื่อ

ใช้ ถอดรหัส Base64 ออนไลน์ ฟรีโดยตรงในเบราว์เซอร์ของคุณ — ไม่ต้องติดตั้ง

ลอง ถอดรหัส Base64 ออนไลน์ ออนไลน์ →

เมื่อผมต้อง debug ปัญหาการยืนยันตัวตนบน production สิ่งแรกที่ผมหยิบมาใช้คือ ตัวถอดรหัส Base64 — JWT payload, webhook signature, และค่า config ที่เข้ารหัสไว้ ล้วนซ่อนอยู่ภายในสตริง Base64 JavaScript มีสองวิธีหลักในการ base64 decode: atob() (browser + Node.js 16+) และ Buffer.from(encoded, 'base64').toString() (Node.js) — และทั้งสองมีพฤติกรรมที่แตกต่างกันมากเมื่อข้อมูลต้นฉบับมีอักขระ Unicode สำหรับการ decode แบบครั้งเดียวโดยไม่ต้องเขียนโค้ด ตัวถอดรหัส Base64 ของ ToolDeck จัดการได้ทันทีในเบราว์เซอร์ของคุณ คู่มือนี้ครอบคลุมทั้งสองสภาพแวดล้อม — มุ่งเป้าไปที่ Node.js 16+ และเบราว์เซอร์สมัยใหม่ (Chrome 80+, Firefox 75+, Safari 14+) — พร้อม ตัวอย่างที่พร้อมใช้งานจริง: การกู้คืน UTF-8, ตัวแปร URL-safe, การ decode JWT, ไฟล์, การตอบสนอง API, Node.js streams, และสี่ข้อผิดพลาดที่มักสร้างผลลัพธ์ที่เสียหายใน codebase จริง

  • atob(encoded) พร้อมใช้งานแบบ native ในเบราว์เซอร์และใน Node.js 16+ แบบ global แต่คืนค่า binary string — ใช้ TextDecoder เพื่อกู้คืนข้อความ UTF-8 จากเนื้อหาใดก็ตามที่สูงกว่า ASCII
  • Buffer.from(encoded, "base64").toString("utf8") คือแนวทางมาตรฐานของ Node.js และจัดการ UTF-8 โดยอัตโนมัติโดยไม่ต้องมีขั้นตอนเพิ่มเติม
  • URL-safe Base64 (ใช้ใน JWT) แทน + ด้วย -, / ด้วย _, และตัด padding = ออก กู้คืนอักขระเหล่านี้ก่อนเรียก atob() หรือใช้ Buffer.from(encoded, "base64url").toString() ใน Node.js 18+
  • ลบ whitespace และ newline ก่อน decode — GitHub Contents API และ MIME encoder หลายตัวตัดบรรทัด Base64 output ที่ 60–76 อักขระต่อบรรทัด
  • Uint8Array.prototype.fromBase64() (TC39 Stage 3) พร้อมใช้งานแล้วใน Node.js 22+ และ Chrome 130+ และจะรวมทั้งสองสภาพแวดล้อมในที่สุด

Base64 Decoding คืออะไร?

Base64 decoding คือการย้อนกลับของ encoding — มันแปลงการแสดง ASCII 64 อักขระกลับ เป็นข้อมูลไบนารีหรือข้อความต้นฉบับ ทุก 4 อักขระ Base64 จะแมปกลับไปยัง 3 ไบต์ พอดี อักขระ padding = ที่ท้ายสตริงที่เข้ารหัสแจ้ง decoder ว่ามีกี่ไบต์เพิ่มเติมที่ถูกเพิ่มเข้าไปเพื่อ ให้กลุ่ม 3 ไบต์สุดท้ายสมบูรณ์

Base64 ไม่ใช่การเข้ารหัส — การดำเนินการนี้สามารถย้อนกลับได้อย่างสมบูรณ์โดยใครก็ตาม ที่มีสตริงที่เข้ารหัส จุดประสงค์คือความปลอดภัยในการส่ง: โปรโตคอลและรูปแบบการจัดเก็บ ที่ออกแบบมาสำหรับข้อความ ASCII 7 บิตไม่สามารถจัดการไบต์ไบนารีตามอำเภอใจได้ และ Base64 เชื่อมช่องว่างนั้น สถานการณ์การ decode JavaScript ทั่วไปได้แก่ การตรวจสอบ JWT payload, การแกะ JSON config ที่เข้ารหัส Base64 จากตัวแปรสภาพแวดล้อม, การแยก เนื้อหาไฟล์ไบนารีจาก REST API, และการ decode data URI ในเบราว์เซอร์

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

atob() — ฟังก์ชัน Decode แบบ Native ของเบราว์เซอร์

atob() (ASCII-to-binary) มีใน เบราว์เซอร์ตั้งแต่ IE10 และกลายเป็น global ใน Node.js 16.0 ซึ่งเป็นส่วนหนึ่งของ โครงการความเข้ากันได้ WinterCG มันยังทำงานแบบ native ใน Deno, Bun, และ Cloudflare Workers โดยไม่ต้อง import

ฟังก์ชันนี้คืนค่า binary string: สตริง JavaScript ที่แต่ละอักขระมี code point เท่ากับค่า byte ดิบหนึ่งค่า (0–255) สิ่งนี้สำคัญ: หากข้อมูลต้นฉบับเป็นข้อความ UTF-8 ที่มีอักขระสูงกว่า U+007F (ตัวอักษรที่มีเครื่องหมาย, Cyrillic, CJK, emoji), สตริงที่ คืนมาคือลำดับ byte ดิบ ไม่ใช่ข้อความที่อ่านได้ ใช้ TextDecoder เพื่อกู้คืนมัน (ครอบคลุมในส่วนถัดไป)

ตัวอย่างการทำงานขั้นต่ำ

JavaScript (browser / Node.js 16+)
// Decoding an HTTP Basic Auth credential pair received in a request header
// Authorization: Basic ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=

function parseBasicAuth(header: string): { serviceId: string; apiKey: string } {
  const base64Part = header.replace(/^Basics+/i, '')
  const decoded    = atob(base64Part)
  const [serviceId, apiKey] = decoded.split(':')
  return { serviceId, apiKey }
}

const auth = parseBasicAuth('Basic ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=')

console.log(auth.serviceId) // deploy-bot
console.log(auth.apiKey)    // sk-prod-a7f2c91e4b3d8

การตรวจสอบ round-trip

JavaScript
// Verify lossless recovery for ASCII-only content
const original = 'service:payments region:eu-west-1 env:production'

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

console.log(encoded)
// c2VydmljZTpwYXltZW50cyByZWdpb246ZXUtd2VzdC0xIGVudjpwcm9kdWN0aW9u

console.log(decoded === original) // true
หมายเหตุ:atob() และ btoa() เป็นส่วนหนึ่งของ WinterCG Minimum Common API — spec เดียวกับที่ควบคุม Fetch, URL, และ crypto ใน runtime ที่ไม่ใช่เบราว์เซอร์ ทั้งสองทำงานเหมือนกันใน Node.js 16+, Bun, Deno, และ Cloudflare Workers

การกู้คืนข้อความ UTF-8 หลัง Decode

ปัญหาที่พบบ่อยที่สุดกับ atob() คือ การเข้าใจผิดเกี่ยวกับประเภทการคืนค่า เมื่อข้อความต้นฉบับถูกเข้ารหัสเป็น UTF-8 ก่อน Base64, atob() จะคืนค่า binary string แบบ Latin-1 ไม่ใช่ข้อความที่อ่านได้:

JavaScript
// 'Алексей Иванов' was UTF-8 encoded then Base64 encoded before transmission
const encoded = '0JDQu9C10LrRgdC10Lkg0JjQstCw0L3QvtCy'

// ❌ atob() returns the raw UTF-8 bytes as a Latin-1 string — garbled output
console.log(atob(encoded))
// "Алексей Р˜РІР°РЅРѕРІ"  ← byte values misread as Latin-1

วิธีที่ถูกต้องคือใช้ TextDecoder เพื่อตีความ byte ดิบเหล่านั้นเป็น UTF-8:

วิธี TextDecoder — ปลอดภัยสำหรับ output Unicode ทุกรูปแบบ

JavaScript (browser + Node.js 16+)
// Unicode-safe Base64 decode utilities
function fromBase64(encoded: string): string {
  const binary = atob(encoded)
  const bytes  = Uint8Array.from(binary, ch => ch.charCodeAt(0))
  return new TextDecoder().decode(bytes)
}

function toBase64(text: string): string {
  const bytes = new TextEncoder().encode(text)
  const chars = Array.from(bytes, byte => String.fromCharCode(byte))
  return btoa(chars.join(''))
}

// Works with any language or script
const orderNote = 'Confirmed: 田中太郎 — São Paulo warehouse, qty: 250'
const encoded   = toBase64(orderNote)
const decoded   = fromBase64(encoded)

console.log(decoded === orderNote) // true
console.log(decoded)
// Confirmed: 田中太郎 — São Paulo warehouse, qty: 250
หมายเหตุ:ใน Node.js ข้ามขั้นตอน TextDecoder ไปเลย — ใช้ Buffer.from(encoded, 'base64').toString('utf8')มันตีความ byte ที่ถอดรหัสเป็น UTF-8 โดยอัตโนมัติและเร็วกว่าสำหรับ input ขนาดใหญ่

Buffer.from() ใน Node.js — คู่มือ Decode ฉบับสมบูรณ์

ใน Node.js, Buffer คือ API มาตรฐาน สำหรับการดำเนินการไบนารีทั้งหมดรวมถึงการ decode Base64 มันจัดการ UTF-8 แบบ native, คืนค่า Buffer ที่แท้จริง (ปลอดภัยสำหรับ ไบนารี), และตั้งแต่ Node.js 18 รองรับ shortcut encoding 'base64url' สำหรับตัวแปร URL-safe

Decode config จากตัวแปรสภาพแวดล้อม

Node.js
// Server config stored as Base64 in an env variable (avoids JSON escaping in shell)
// DB_CONFIG=eyJob3N0IjoiZGItcHJpbWFyeS5pbnRlcm5hbCIsInBvcnQiOjU0MzIsImRhdGFiYXNlIjoiYW5hbHl0aWNzX3Byb2QiLCJtYXhDb25uZWN0aW9ucyI6MTAwfQ==

const raw = Buffer.from(process.env.DB_CONFIG!, 'base64').toString('utf8')
const dbConfig = JSON.parse(raw)

console.log(dbConfig.host)           // db-primary.internal
console.log(dbConfig.port)           // 5432
console.log(dbConfig.maxConnections) // 100

กู้คืนไฟล์ไบนารีจากไฟล์ .b64

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

// Read the Base64-encoded certificate and restore the original binary
const encoded = readFileSync(join(process.cwd(), 'dist', 'cert.b64'), 'utf8').trim()
const certBuf  = Buffer.from(encoded, 'base64')

writeFileSync('./ssl/server.crt', certBuf)

console.log(`Restored ${certBuf.length} bytes`)
// Restored 2142 bytes

Decode แบบ async พร้อมการจัดการ error

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

async function decodeBase64File(
  encodedPath: string,
  outputPath:  string,
): Promise<number> {
  try {
    const encoded = await readFile(encodedPath, 'utf8')
    const binary  = Buffer.from(encoded.trim(), 'base64')
    await writeFile(outputPath, binary)
    return binary.length
  } catch (err) {
    const code = (err as NodeJS.ErrnoException).code
    if (code === 'ENOENT') throw new Error(`File not found: ${encodedPath}`)
    if (code === 'EACCES') throw new Error(`Permission denied: ${encodedPath}`)
    throw err
  }
}

// Restore a PDF stored as Base64
const bytes = await decodeBase64File('./uploads/invoice.b64', './out/invoice.pdf')
console.log(`Decoded ${bytes} bytes — PDF restored`)

ฟังก์ชัน Decode Base64 — อ้างอิงพารามิเตอร์

อ้างอิงด่วนสำหรับพารามิเตอร์ของ native decoding API หลักทั้งสอง จัดรูปแบบไว้สำหรับ ใช้ค้นหาเมื่อเขียนหรือรีวิวโค้ด

atob(encodedData)

พารามิเตอร์ประเภทจำเป็นคำอธิบาย
encodedDatastringใช่สตริง Base64 มาตรฐานที่ใช้อักขระ +, /, = ตัวแปร URL-safe (-, _) จะ throw InvalidCharacterError ไม่อนุญาต whitespace
คืนค่า: binary string — code point ของแต่ละอักขระเท่ากับค่า byte ดิบหนึ่งค่า (0–255) ไม่ใช่สตริง Unicode; ส่งผ่าน TextDecoder เพื่อกู้คืนข้อความ UTF-8

Buffer.from(input, inputEncoding) / .toString(outputEncoding)

พารามิเตอร์ประเภทค่าเริ่มต้นคำอธิบาย
inputstring | Buffer | TypedArray | ArrayBufferจำเป็นสตริงที่เข้ารหัส Base64 ที่จะ decode หรือ buffer ที่มี byte ที่เข้ารหัส
inputEncodingBufferEncoding"utf8"ตั้งเป็น "base64" สำหรับ Base64 มาตรฐาน (RFC 4648 §4) หรือ "base64url" สำหรับ URL-safe Base64 (RFC 4648 §5, Node.js 18+)
outputEncodingstring"utf8"Encoding สำหรับ output ของ .toString() ใช้ "utf8" สำหรับข้อความที่อ่านได้ "binary" สำหรับ binary string แบบ Latin-1 ที่เข้ากันได้กับ output ของ atob()
startinteger0Byte offset ภายใน Buffer ที่ decode แล้วเพื่อเริ่มอ่าน ส่งไปยัง .toString() เป็นอาร์กิวเมนต์ที่สอง
endintegerbuf.lengthByte offset ที่จะหยุดอ่าน (exclusive) ส่งไปยัง .toString() เป็นอาร์กิวเมนต์ที่สาม
คืนค่า: Buffer จาก .from() คืนค่า string จาก .toString() เก็บเป็น Buffer (อย่าเรียก .toString()) เมื่อเนื้อหาที่ decode แล้วเป็นไบนารี — รูปภาพ, PDF, เสียง

URL-safe Base64 — Decode JWT และพารามิเตอร์ URL

JWT ใช้ URL-safe Base64 (RFC 4648 §5) สำหรับทั้งสามส่วน URL-safe Base64 แทน + ด้วย - และ / ด้วย _, และตัด padding = ที่ท้ายออก การส่งตรงไปยัง atob() โดยไม่กู้คืนจะสร้าง output ที่ผิดหรือ throw error

Browser — กู้คืนอักขระและ padding ก่อน decode

JavaScript (browser)
function decodeBase64Url(input: string): string {
  const base64 = input.replace(/-/g, '+').replace(/_/g, '/')
  const padded = base64 + '==='.slice(0, (4 - base64.length % 4) % 4)
  const binary = atob(padded)
  const bytes  = Uint8Array.from(binary, ch => ch.charCodeAt(0))
  return new TextDecoder().decode(bytes)
}

// Inspect a JWT payload segment (the middle part between the two dots)
const jwtToken  = 'eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2U4YjRkIiwicm9sZSI6ImVkaXRvciIsIndvcmtzcGFjZUlkIjoid3NfM2E3ZjkxYzIiLCJleHAiOjE3MTcyMDM2MDB9'
const payload   = decodeBase64Url(jwtToken)
const claims    = JSON.parse(payload)

console.log(claims.userId)      // usr_9f2a1c3e8b4d
console.log(claims.role)        // editor
console.log(claims.workspaceId) // ws_3a7f91c2

Node.js 18+ — encoding 'base64url' แบบ native

Node.js 18+
// Node.js 18 added 'base64url' as a first-class Buffer encoding — no manual replace needed
function decodeJwtSegment(segment: string): Record<string, unknown> {
  const json = Buffer.from(segment, 'base64url').toString('utf8')
  return JSON.parse(json)
}

const token   = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2U4YjRkIiwicm9sZSI6ImVkaXRvciIsIndvcmtzcGFjZUlkIjoid3NfM2E3ZjkxYzIiLCJleHAiOjE3MTcyMDM2MDB9.SIGNATURE'
const [headerB64, payloadB64] = token.split('.')

const header  = decodeJwtSegment(headerB64)
const payload = decodeJwtSegment(payloadB64)

console.log(header.alg)          // HS256
console.log(payload.role)        // editor
console.log(payload.workspaceId) // ws_3a7f91c2

Decode Base64 จากไฟล์และการตอบสนอง API

ในโค้ด production การ decode Base64 มักเกิดขึ้นมากที่สุดเมื่อใช้ API ภายนอกที่ส่ง เนื้อหาในรูปแบบที่เข้ารหัส ทั้งสองสถานการณ์มี gotcha สำคัญเกี่ยวกับ whitespace และ output ไบนารีเทียบกับข้อความ หากคุณแค่ต้องการตรวจสอบ response ที่เข้ารหัสระหว่าง debug ให้วางลงใน ตัวถอดรหัส Base64 โดยตรง — จัดการได้ทันทีทั้งโหมดมาตรฐานและ URL-safe

Decode เนื้อหาจาก GitHub Contents API

JavaScript
// GitHub Contents API returns file content as Base64, wrapped at 60 chars per line
async function fetchDecodedFile(
  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 }
  if (data.encoding !== 'base64') throw new Error(`Unexpected encoding: ${data.encoding}`)

  // ⚠️ GitHub wraps at 60 chars — strip newlines before decoding
  const clean = data.content.replace(/\n/g, '')
  return Buffer.from(clean, 'base64').toString('utf8')
}

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

Decode ไบนารีที่เข้ารหัส Base64 จาก API (browser)

JavaScript (browser)
// Some APIs return binary content (images, PDFs) as Base64 JSON fields
async function downloadDecodedFile(endpoint: string, authToken: string): Promise<void> {
  const res = await fetch(endpoint, { headers: { Authorization: `Bearer ${authToken}` } })
  if (!res.ok) throw new Error(`Download failed: ${res.status}`)

  const { filename, content, mimeType } = await res.json() as {
    filename: string; content: string; mimeType: string
  }

  // Decode Base64 → binary bytes → Blob
  const binary = atob(content)
  const bytes  = Uint8Array.from(binary, ch => ch.charCodeAt(0))
  const blob   = new Blob([bytes], { type: mimeType })

  // Trigger browser download
  const url = URL.createObjectURL(blob)
  const a   = Object.assign(document.createElement('a'), { href: url, download: filename })
  a.click()
  URL.revokeObjectURL(url)
}

await downloadDecodedFile('/api/reports/latest', sessionStorage.getItem('auth_token')!)

Decode Base64 ผ่าน Command-Line Node.js และ Shell

สำหรับ script CI/CD, เซสชัน debug, หรืองาน decode แบบครั้งเดียว เครื่องมือ shell และ one-liner ของ Node.js เร็วกว่า script เต็มรูปแบบ โปรดทราบว่าชื่อ flag แตกต่างกัน ระหว่าง macOS และ Linux

bash
# ── macOS / Linux system base64 ───────────────────────────────────────
# Standard decoding (macOS uses -D, Linux uses -d)
echo "ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=" | base64 -d   # Linux
echo "ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=" | base64 -D   # macOS

# Decode a .b64 file to its original binary
base64 -d ./dist/cert.b64 > ./ssl/server.crt       # Linux
base64 -D -i ./dist/cert.b64 -o ./ssl/server.crt   # macOS

# URL-safe Base64 — restore + and / before decoding
echo "eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2UifQ" | tr '-_' '+/' | base64 -d

# ── Node.js one-liner — works on Windows too ───────────────────────────
node -e "process.stdout.write(Buffer.from(process.argv[1], 'base64').toString())" "ZGVwbG95LWJvdA=="
# deploy-bot

# URL-safe (Node.js 18+)
node -e "process.stdout.write(Buffer.from(process.argv[1], 'base64url').toString())" "eyJhbGciOiJIUzI1NiJ9"
# {"alg":"HS256"}
หมายเหตุ:บน macOS, base64 ใช้ -D เพื่อ decode (ตัวพิมพ์ใหญ่ D), ในขณะที่ Linux ใช้ -d (ตัวพิมพ์เล็ก) สิ่งนี้ทำให้ script CI เสียหายอย่างเงียบๆ — ใช้ one-liner ของ Node.js เมื่อไม่รับประกันว่าแพลตฟอร์มเป้าหมายเป็น Linux

ทางเลือกประสิทธิภาพสูง: js-base64

เหตุผลหลักที่จะใช้ library คือความสอดคล้องข้ามสภาพแวดล้อม หากคุณส่ง package ที่ ทำงานในทั้ง browser และ Node.js โดยไม่มีการกำหนดค่า bundler, Buffer ต้องการการตรวจจับสภาพแวดล้อม และ atob() ต้องการ workaround TextDecoder js-base64 (100M+ ดาวน์โหลด npm ต่อสัปดาห์) จัดการทั้งสองอย่างโปร่งใส

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

// Standard decoding — Unicode-safe, works in browser and Node.js
const raw   = fromBase64('eyJldmVudElkIjoiZXZ0XzdjM2E5ZjFiMmQiLCJ0eXBlIjoiY2hlY2tvdXRfY29tcGxldGVkIiwiY3VycmVuY3kiOiJFVVIiLCJhbW91bnQiOjE0OTAwfQ==')
const event = JSON.parse(raw)
console.log(event.type)     // checkout_completed
console.log(event.currency) // EUR

// URL-safe decoding — no manual character replacement needed
const jwtPayload = fromBase64Url('eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2U4YjRkIiwicm9sZSI6ImVkaXRvciJ9')
const claims     = JSON.parse(jwtPayload)
console.log(claims.role) // editor

// Validate before decoding untrusted input
const untrusted = 'not!valid@base64#'
if (!isValid(untrusted)) {
  console.error('Rejected: invalid Base64 input')
}

// Binary output — second argument true returns Uint8Array
const pngBytes = fromBase64('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', true)
console.log(pngBytes instanceof Uint8Array) // true

ผลลัพธ์ Terminal พร้อม Syntax Highlighting

เมื่อเขียนเครื่องมือ debug CLI หรือ script ตรวจสอบ, output console.log ธรรมดาอ่านยากสำหรับ JSON payload ขนาดใหญ่ chalk (package npm ที่ดาวน์โหลดมากที่สุดสำหรับการระบายสีใน terminal) รวมกับการ decode Base64 สร้าง output terminal ที่อ่านได้ง่ายและสแกนได้ — มีประโยชน์สำหรับการตรวจสอบ JWT, debug API response, และการตรวจสอบ config

bash
npm install chalk
# chalk v5+ is ESM-only — use import, not require
Node.js
import chalk from 'chalk'

// Decode and display any Base64 value with smart type detection
function inspectBase64(encoded: string, label = 'Decoded value'): void {
  let decoded: string
  try {
    decoded = Buffer.from(encoded.trim(), 'base64').toString('utf8')
  } catch {
    console.error(chalk.red('✗ Invalid Base64 input'))
    return
  }

  console.log(chalk.bold.cyan(`\n── ${label} ──`))

  // Attempt JSON pretty-print
  try {
    const parsed = JSON.parse(decoded)
    console.log(chalk.green('Type:'), chalk.yellow('JSON'))
    for (const [key, value] of Object.entries(parsed)) {
      const display = typeof value === 'object' ? JSON.stringify(value) : String(value)
      console.log(chalk.green(`  ${key}:`), chalk.white(display))
    }
    return
  } catch { /* not JSON */ }

  // Plain text fallback
  console.log(chalk.green('Type:'), chalk.yellow('text'))
  console.log(chalk.white(decoded))
}

// Inspect a Base64-encoded JWT payload
const tokenParts = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2U4YjRkIiwicm9sZSI6ImVkaXRvciIsImV4cCI6MTcxNzIwMzYwMH0.SIGNATURE'.split('.')
inspectBase64(tokenParts[0], 'JWT Header')
inspectBase64(tokenParts[1], 'JWT Payload')
// ── JWT Header ──
// Type:   JSON
//   alg:  HS256
//   typ:  JWT
//
// ── JWT Payload ──
// Type:   JSON
//   userId: usr_9f2a1c3e8b4d
//   role:   editor
//   exp:    1717203600
หมายเหตุ:ใช้ chalk สำหรับ output terminal/CLI เท่านั้น — ไม่ใช่สำหรับเนื้อหาที่เขียนลงไฟล์, API response, หรือ log aggregator รหัส escape ANSI ทำให้ consumer ที่ไม่ใช่ terminal เสียหาย: แพลตฟอร์ม log (Datadog, Splunk), JSON log parser, และ CI log viewer ทั้งหมด แสดงผลเป็นลำดับอักขระที่อ่านไม่ได้

Decode ไฟล์ Base64 ขนาดใหญ่ด้วย Node.js Streams

เมื่อไฟล์ที่เข้ารหัส Base64 เกิน ~50 MB การโหลดทั้งหมดเข้าหน่วยความจำด้วย readFileSync() กลายเป็นปัญหา Node.js streams ช่วยให้คุณ decode ข้อมูลเป็น chunk — แต่ Base64 ต้องการ 4 อักขระ คูณต่อ chunk (แต่ละกลุ่ม 4 อักขระ decode เป็น 3 ไบต์ พอดี) เพื่อหลีกเลี่ยง error padding ที่ขอบ chunk

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

async function streamDecodeBase64(inputPath: string, outputPath: string): Promise<void> {
  const readStream  = createReadStream(inputPath, { encoding: 'utf8', highWaterMark: 4 * 1024 * 192 })
  const writeStream = createWriteStream(outputPath)

  let buffer = ''

  await pipeline(
    readStream,
    async function* (source) {
      for await (const chunk of source) {
        buffer += (chunk as string).replace(/\s/g, '') // strip any whitespace/newlines

        // Decode only complete 4-char groups to avoid mid-stream padding issues
        const remainder = buffer.length % 4
        const safe      = buffer.slice(0, buffer.length - remainder)
        buffer          = buffer.slice(buffer.length - remainder)

        if (safe.length > 0) yield Buffer.from(safe, 'base64')
      }
      if (buffer.length > 0) yield Buffer.from(buffer, 'base64')
    },
    writeStream,
  )
}

// Decode a 200 MB video that was stored as Base64
await streamDecodeBase64('./uploads/product-demo.b64', './dist/product-demo.mp4')
console.log('Stream decode complete')
หมายเหตุ:ขนาด chunk ต้องเป็นคูณของ 4 อักขระเมื่ออ่านข้อความ Base64 ดังนั้นแต่ละ chunk จะมีเฉพาะกลุ่ม 4 อักขระที่สมบูรณ์ ตัวอย่างใช้ 4 × 1024 × 192 = 786,432 อักขระ (768 KB) สำหรับไฟล์ที่น้อยกว่า 50 MB, readFile() + Buffer.from(content.trim(), 'base64') ง่ายกว่าและเร็วพอ

ข้อผิดพลาดที่พบบ่อย

ผมเห็นข้อผิดพลาดสี่ข้อนี้ใน JavaScript codebase ซ้ำๆ — มักซ่อนตัวอยู่จนกว่า อักขระที่ไม่ใช่ ASCII หรือ API response ที่มีการตัดบรรทัดจะถึงเส้นทาง decode ใน production

ข้อผิดพลาดที่ 1 — ใช้ atob() โดยไม่มี TextDecoder สำหรับเนื้อหา UTF-8

ปัญหา: atob() คืนค่า binary string ที่แต่ละ อักขระเป็นค่า byte ดิบหนึ่งค่า ลำดับ multi-byte UTF-8 (Cyrillic, CJK, อักขระที่มีเครื่องหมาย) ปรากฏเป็นอักขระ Latin-1 ที่อ่านไม่ได้ วิธีแก้: ห่อ output ใน TextDecoder

Before · JavaScript
After · JavaScript
// ❌ atob() returns the raw UTF-8 bytes as a Latin-1 string
const encoded = '0JDQu9C10LrRgdC10Lkg0JjQstCw0L3QvtCy'
const decoded  = atob(encoded)
console.log(decoded)
// "Алексей Р˜РІР°РЅРѕРІ"  ← wrong
// ✅ Use TextDecoder to correctly interpret the UTF-8 bytes
const encoded  = '0JDQu9C10LrRgdC10Lkg0JjQstCw0L3QvtCy'
const binary   = atob(encoded)
const bytes    = Uint8Array.from(binary, ch => ch.charCodeAt(0))
const decoded  = new TextDecoder().decode(bytes)
console.log(decoded) // Алексей Иванов ✓

ข้อผิดพลาดที่ 2 — ส่ง URL-safe Base64 โดยตรงไปยัง atob()

ปัญหา: ส่วนของ JWT ใช้ - และ _ แทน + และ /, โดยไม่มี padding atob() อาจคืนค่าข้อมูลที่ผิดหรือ throw วิธีแก้: กู้คืนอักขระมาตรฐานและเพิ่ม padding ก่อน

Before · JavaScript
After · JavaScript
// ❌ URL-safe JWT segment passed directly — unreliable
const jwtPayload = 'eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2UifQ'
const decoded    = atob(jwtPayload) // May produce wrong result or throw
// ✅ Restore standard Base64 chars 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)
  const bin  = atob(pad)
  const bytes = Uint8Array.from(bin, ch => ch.charCodeAt(0))
  return new TextDecoder().decode(bytes)
}
const decoded = decodeBase64Url('eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2UifQ')
// {"userId":"usr_9f2a1c3e"} ✓

ข้อผิดพลาดที่ 3 — ไม่ลบ newline จาก Base64 ที่ถูกตัดบรรทัด

ปัญหา: GitHub Contents API และ MIME encoder ตัดบรรทัด Base64 output ที่ 60–76 อักขระ ต่อบรรทัด atob() throw InvalidCharacterError บนอักขระ \n วิธีแก้: ลบ whitespace ทั้งหมดก่อน decode

Before · JavaScript
After · JavaScript
// ❌ GitHub API content field contains embedded newlines
const data    = await res.json()
const decoded = atob(data.content) // ❌ throws InvalidCharacterError
// ✅ Strip newlines (and any other whitespace) before decoding
const data    = await res.json()
const clean   = data.content.replace(/\s/g, '')
const decoded = atob(clean) // ✓

ข้อผิดพลาดที่ 4 — เรียก .toString() บนเนื้อหาไบนารีที่ decode แล้ว

ปัญหา: เมื่อข้อมูลต้นฉบับเป็นไบนารี (รูปภาพ, PDF, เสียง), การเรียก .toString('utf8') จะแทนที่ ลำดับ byte ที่ไม่รู้จักด้วย U+FFFD, ทำให้ output เสียหายอย่างเงียบๆ วิธีแก้: เก็บผลลัพธ์เป็น Buffer — อย่าแปลงเป็น string

Before · JavaScript
After · JavaScript
// ❌ .toString('utf8') corrupts binary content
import { readFileSync, writeFileSync } from 'node:fs'
const encoded   = readFileSync('./uploads/invoice.b64', 'utf8').trim()
const corrupted = Buffer.from(encoded, 'base64').toString('utf8') // ❌
writeFileSync('./out/invoice.pdf', corrupted) // ❌ unreadable PDF
// ✅ Keep the Buffer as binary — do not convert to a string
import { readFileSync, writeFileSync } from 'node:fs'
const encoded = readFileSync('./uploads/invoice.b64', 'utf8').trim()
const binary  = Buffer.from(encoded, 'base64') // ✓ raw bytes preserved
writeFileSync('./out/invoice.pdf', binary)      // ✓ valid PDF

วิธี Decode Base64 ใน JavaScript — เปรียบเทียบอย่างย่อ

วิธีOutput UTF-8Output ไบนารีURL-safeสภาพแวดล้อมต้องติดตั้ง
atob()❌ ต้องใช้ TextDecoder✅ binary string❌ กู้คืนด้วยตนเองBrowser, Node 16+, Bun, Denoไม่
TextDecoder + atob()✅ UTF-8✅ ผ่าน Uint8Array❌ กู้คืนด้วยตนเองBrowser, Node 16+, Denoไม่
Buffer.from().toString()✅ utf8✅ เก็บเป็น Buffer✅ base64url (Node 18+)Node.js, Bunไม่
Uint8Array.fromBase64() (TC39)✅ ผ่าน TextDecoder✅ native✅ ตัวเลือก alphabetChrome 130+, Node 22+ไม่
js-base64✅ เสมอ✅ Uint8Array✅ ในตัวUniversalnpm install

เลือก atob() เฉพาะเมื่อเนื้อหาที่ decode แล้วรับประกันว่าเป็นข้อความ ASCII ล้วน สำหรับข้อความหลายภาษาในเบราว์เซอร์ ให้ใช้ TextDecoder + atob() สำหรับโค้ด server-side ใน Node.js ให้ใช้ Buffer เป็นค่าเริ่มต้น — มันจัดการ UTF-8 โดยอัตโนมัติและเก็บข้อมูลไบนารีไว้ครบถ้วน สำหรับ library ข้ามสภาพแวดล้อม js-base64 ขจัด edge case ทั้งหมด

คำถามที่พบบ่อย

ทำไม atob() ถึงคืนค่าอักขระที่อ่านไม่ได้แทนที่จะเป็นข้อความปกติ?
atob() คืนค่า binary string ที่แต่ละอักขระแสดงถึง byte ดิบหนึ่งค่า (0–255) ไม่ใช่ Unicode code point หากข้อความต้นฉบับถูกเข้ารหัสเป็น UTF-8 อักขระใดก็ตามที่สูงกว่า U+007F — Cyrillic, Arabic, ideograph CJK, ตัวอักษรที่มีเครื่องหมาย — จะปรากฏเป็นอักขระ Latin-1 ที่อ่านไม่ได้สองตัวหรือมากกว่า วิธีแก้: ส่ง output ผ่าน TextDecoder: const bytes = Uint8Array.from(atob(encoded), ch => ch.charCodeAt(0)); const text = new TextDecoder().decode(bytes) ใน Node.js ใช้ Buffer.from(encoded, 'base64').toString('utf8') ซึ่งจัดการสิ่งนี้โดยอัตโนมัติ
จะ decode JWT token payload ใน JavaScript ได้อย่างไร?
JWT มีสาม segment URL-safe Base64 ที่คั่นด้วยจุด: header.payload.signature เพื่อ decode payload: const [, payloadB64] = token.split('.') ในเบราว์เซอร์: กู้คืนอักขระมาตรฐาน, เพิ่ม padding, decode ด้วย atob() และ TextDecoder ใน Node.js 18+: Buffer.from(payloadB64, 'base64url').toString('utf8') สำคัญ: การ decode เท่านั้นที่เปิดเผย claim — มันไม่ยืนยัน signature ใช้ JWT library ที่เหมาะสม (jsonwebtoken, jose) สำหรับการ decode ที่ยืนยันแล้วใน production
ความแตกต่างระหว่าง atob() และ Buffer.from() สำหรับการ decode คืออะไร?
atob() มีใน JavaScript environment ทั้งหมด (browser, Node.js 16+, Bun, Deno) โดยไม่ต้อง import แต่คืนค่า binary string — คุณต้องใช้ TextDecoder เพื่อแปลงเนื้อหา UTF-8 เป็นข้อความที่อ่านได้ Buffer.from(encoded, 'base64') สำหรับ Node.js / Bun เท่านั้น คืนค่า Buffer จริง (ปลอดภัยสำหรับไบนารี), จัดการ UTF-8 แบบ native, และรองรับ 'base64url' ใน Node.js 18+ สำหรับโค้ด server-side Buffer ง่ายกว่า สำหรับโค้ด browser atob() + TextDecoder คือมาตรฐาน สำหรับ library ข้ามสภาพแวดล้อม js-base64 ช่วย abstract ความแตกต่าง
จะ decode URL-safe Base64 ในเบราว์เซอร์ได้อย่างไร?
URL-safe Base64 แทน + ด้วย -, / ด้วย _, และตัด padding = ออก กู้คืนก่อนเรียก atob(): const b64 = input.replace(/-/g, '+').replace(/_/g, '/'); const padded = b64 + '==='.slice(0, (4 - b64.length % 4) % 4); const text = new TextDecoder().decode(Uint8Array.from(atob(padded), c => c.charCodeAt(0))) ใน Node.js 18+: Buffer.from(input, 'base64url').toString('utf8') จัดการในการเรียกครั้งเดียว
จะ decode เนื้อหา Base64 จาก GitHub API ใน JavaScript ได้อย่างไร?
GitHub Contents API คืนค่าเนื้อหาไฟล์เป็น Base64 มาตรฐานพร้อมอักขระ newline ทุก 60 อักขระ ลบออกก่อน decode: const clean = data.content.replace(/\n/g, '') ในเบราว์เซอร์: new TextDecoder().decode(Uint8Array.from(atob(clean), c => c.charCodeAt(0))) ใน Node.js: Buffer.from(clean, 'base64').toString('utf8') สำหรับไฟล์ไบนารี (รูปภาพ, PDF) เก็บ Buffer โดยไม่เรียก .toString() — ส่งตรงไปยัง writeFile หรือ response stream
สามารถ decode รูปภาพที่เข้ารหัส Base64 ใน JavaScript โดยไม่ใช้ library ได้ไหม?
ได้ ในเบราว์เซอร์: const binary = atob(encoded); const bytes = Uint8Array.from(binary, ch => ch.charCodeAt(0)); const blob = new Blob([bytes], { type: 'image/png' }); const url = URL.createObjectURL(blob) สำหรับ img src สร้าง data URI แทน: const src = 'data:image/png;base64,' + encoded — ข้ามขั้นตอน decode ไปเลย ใน Node.js: Buffer.from(encoded, 'base64') แล้ว writeFileSync('./out.png', buffer) กฎสำคัญ: อย่าเรียก .toString() บน Buffer ที่ decode แล้วเมื่อเนื้อหาเป็นไบนารี

เครื่องมือที่เกี่ยวข้อง

สำหรับการ decode ด้วยคลิกเดียวโดยไม่ต้องเขียนโค้ด วาง Base64 string ของคุณลงใน ตัวถอดรหัส Base64 โดยตรง — จัดการทั้งโหมดมาตรฐานและ URL-safe พร้อม output ทันทีในเบราว์เซอร์ของคุณ

มีให้ในภาษาอื่นด้วย:PythonGoJavaC#
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 Laurentผู้ตรวจสอบทางเทคนิค

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.