Base64 ใน JavaScript — btoa() & Buffer
ใช้ ตัวเข้ารหัส Base64 ออนไลน์ ฟรีโดยตรงในเบราว์เซอร์ของคุณ — ไม่ต้องติดตั้ง
ลอง ตัวเข้ารหัส Base64 ออนไลน์ ออนไลน์ →เมื่อคุณฝังรูปภาพใน CSS data URI ส่งข้อมูลรับรองตัวตนใน HTTP Authorization header หรือเก็บใบรับรองแบบไบนารีในตัวแปร environment คุณจำเป็นต้องเข้ารหัส Base64 ข้อมูล JavaScript อย่างน่าเชื่อถือทั้งในเบราว์เซอร์และ Node.js JavaScript มี API ในตัวสองแบบที่แตกต่างกัน:btoa() สำหรับสภาพแวดล้อมเบราว์เซอร์ (มีใน Node.js 16+ ด้วย) และ Buffer.from() สำหรับ Node.js — แต่ละแบบมีข้อจำกัดที่แตกต่างกันเกี่ยวกับ Unicode ข้อมูลไบนารี และความปลอดภัยของ URL สำหรับการเข้ารหัสด่วนโดยไม่ต้องเขียนโค้ด Base64 Encoder ของ ToolDeck จัดการได้ทันทีในเบราว์เซอร์ คู่มือนี้ครอบคลุมทั้งสองสภาพแวดล้อมด้วยตัวอย่าง พร้อม production: การจัดการ Unicode, ตัวแปร URL-safe, การเข้ารหัสไฟล์และ API response, การใช้ CLI, และข้อผิดพลาดสี่อย่างที่ก่อให้เกิด bug อย่างสม่ำเสมอใน codebase จริง
- ✓btoa() มีในเบราว์เซอร์แบบ native และเป็น global ใน Node.js 16+ แต่รับเฉพาะ Latin-1 (code point 0–255) เท่านั้น — input Unicode จะ throw DOMException
- ✓Buffer.from(text, "utf8").toString("base64") คือตัวเทียบเท่าใน Node.js ที่จัดการ Unicode แบบ native โดยไม่ต้องมีขั้นตอนเพิ่มเติม
- ✓Base64 URL-safe แทน + → -, / → _ และลบ padding = ออก — ใช้ Buffer.from().toString("base64url") ใน Node.js 18+ สำหรับ one-liner
- ✓สำหรับข้อมูลไบนารี (ArrayBuffer, Uint8Array, ไฟล์) ให้ใช้ Buffer ใน Node.js หรือวิธี arrayBuffer() + Uint8Array ในเบราว์เซอร์ — ไม่ใช้ response.text() เด็ดขาด
- ✓Uint8Array.prototype.toBase64() (TC39 Stage 3) มีใน Node.js 22+ และ Chrome 130+ แล้ว และจะรวมทั้งสองสภาพแวดล้อมให้เป็นหนึ่ง
Base64 Encoding คืออะไร?
Base64 แปลงข้อมูลไบนารีที่กำหนดเองเป็น string ที่สร้างจากอักขระ ASCII ที่พิมพ์ได้ 64 ตัว: A–Z, a–z, 0–9, +, และ / ทุก 3 byte ของ input จะแมปกับ 4 อักขระ Base64 พอดี; หาก input มีความยาวไม่ใช่พหุคูณของ 3 จะเพิ่มอักขระ padding = หนึ่งหรือสองตัว output ที่เข้ารหัสแล้ว จะใหญ่กว่าต้นฉบับประมาณ 33% เสมอ
Base64 ไม่ใช่การเข้ารหัส — ไม่ให้ความลับ ใครก็ตามที่มี string ที่เข้ารหัสแล้ว สามารถถอดรหัสได้ด้วยการเรียกฟังก์ชันครั้งเดียว วัตถุประสงค์คือความปลอดภัยในการส่งข้อมูล: หลาย protocol และรูปแบบการจัดเก็บถูกออกแบบสำหรับข้อความ ASCII 7 บิตและไม่สามารถ จัดการ byte ไบนารีที่กำหนดเองได้ Base64 เชื่อมช่องว่างนั้น กรณีการใช้งาน JavaScript ทั่วไป ได้แก่: data URI สำหรับฝัง asset, HTTP Basic Auth header, ส่วน JWT token, ไฟล์แนบอีเมล MIME และการเก็บ binary blob ใน JSON API
deploy-bot:sk-prod-a7f2c91e4b3d8
ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=
btoa() — ฟังก์ชันเข้ารหัส Native ของเบราว์เซอร์
btoa() (binary-to-ASCII) มีในเบราว์เซอร์ ตั้งแต่ IE10 และกลายเป็น global ใน Node.js 16.0 ในฐานะส่วนหนึ่งของโครงการความเข้ากันได้ WinterCG นอกจากนี้ยังทำงานแบบ native ใน Deno, Bun และ Cloudflare Workers ไม่ต้อง import
ฟังก์ชันรับ argument string หนึ่งตัวและคืน Base64-encoded form ของมัน คู่ตรงกันข้าม atob() (ASCII-to-binary) ถอดรหัสกลับ ทั้งสองแบบ synchronous และทำงานด้วยหน่วยความจำคงที่สัมพันธ์กับขนาด input
ตัวอย่างที่ใช้งานได้น้อยที่สุด
// 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=ถอดรหัสด้วย atob()
// 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
btoa() และ atob() เป็น ส่วนหนึ่งของ WinterCG Minimum Common API — spec เดียวกันที่ควบคุม Fetch, URL และ crypto ใน runtime ที่ไม่ใช่เบราว์เซอร์ ทำงานเหมือนกันใน Node.js 16+, Bun, Deno และ Cloudflare Workersการจัดการ Unicode และอักขระ Non-ASCII
กับดักที่พบบ่อยที่สุดของ btoa() คือข้อจำกัด Latin-1 ที่เข้มงวด อักขระใดก็ตามที่มี code point เกิน U+00FF จะทำให้เกิด exception ทันที:
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วิธีที่ถูกต้องคือเข้ารหัส string เป็น byte UTF-8 ก่อน แล้วจึง Base64-encode byte เหล่านั้น JavaScript มี TextEncoder ไว้สำหรับจุดประสงค์นี้:
วิธี TextEncoder — ปลอดภัยสำหรับ Unicode input ทุกชนิด
// 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 = 'ยืนยัน: สมชาย ใจดี — คลังสินค้ากรุงเทพ, จำนวน: 250'
const encoded = toBase64(orderNote)
const decoded = fromBase64(encoded)
console.log(encoded)
// 4Lml4Liy4Lin4Li44LiX4LiZ4LmM4Liq4Liz4LiZ4LiX4Li14LmA4Lih4LmI...
console.log(decoded === orderNote) // trueBuffer.from(text, 'utf8').toString('base64')วิธีนี้จัดการ Unicode แบบ native และเร็วกว่าสำหรับ string ขนาดใหญ่Buffer.from() ใน Node.js — คู่มือฉบับสมบูรณ์พร้อมตัวอย่าง
ใน Node.js, Buffer คือ idiomatic API สำหรับ การดำเนินการข้อมูลไบนารีทั้งหมด รวมถึงการแปลง encoding มีมาก่อน TextEncoder หลายปี และยังคงเป็นตัวเลือกที่ต้องการสำหรับโค้ดฝั่ง server ข้อดีหลักเมื่อเทียบกับ btoa(): รองรับ UTF-8 แบบ native, จัดการข้อมูลไบนารี, และ shortcut encoding 'base64url' ที่มีตั้งแต่ Node.js 18
การเข้ารหัสและถอดรหัสข้อความพื้นฐาน
// 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เข้ารหัสไฟล์ไบนารีจากดิสก์
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การเข้ารหัสไฟล์แบบ async พร้อมการจัดการ error
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`)ฟังก์ชัน Base64 JavaScript — อ้างอิง Parameter
ต่างจาก module base64 ของ Python, JavaScript ไม่มีฟังก์ชัน Base64 แบบรวมเดียว API ขึ้นอยู่กับสภาพแวดล้อมเป้าหมาย นี่คืออ้างอิงฉบับสมบูรณ์สำหรับวิธีแบบ native ทั้งหมด:
| ฟังก์ชัน | ประเภท input | Unicode | URL-safe | มีใน |
|---|---|---|---|---|
| btoa(string) | string (Latin-1) | ❌ throw เมื่อเกิน U+00FF | ❌ แทนที่ด้วยตัวเอง | Browser, Node 16+, Bun, Deno |
| atob(string) | Base64 string | ❌ คืน binary string | ❌ แทนที่ด้วยตัวเอง | Browser, Node 16+, Bun, Deno |
| Buffer.from(src, enc) .toString(enc) | string | Buffer | Uint8Array | ✅ utf8 encoding | ✅ base64url ใน Node 18+ | Node.js, Bun |
| TextEncoder().encode(str) + btoa() | string (Unicode ใดก็ได้) | ✅ ผ่าน byte UTF-8 | ❌ แทนที่ด้วยตัวเอง | Browser, Node 16+, Deno |
| Uint8Array.toBase64() (TC39) | Uint8Array | ✅ ไบนารี | ✅ omitPadding + alphabet | Chrome 130+, Node 22+ |
signature Buffer.from(src, enc).toString(enc) รับค่า encoding หลายค่าที่เกี่ยวข้องกับ Base64:
Base64 URL-safe — การเข้ารหัสสำหรับ JWT, URL และชื่อไฟล์
Base64 มาตรฐานใช้ + และ / ซึ่งเป็นอักขระสงวนใน URL — + จะถูก decode เป็น space ใน query string และ / คือตัวแบ่ง path JWT, URL parameter, ชื่อไฟล์ และค่า cookie ล้วนต้องการตัวแปร URL-safe: + → -, / → _, ลบ = ท้าย
เบราว์เซอร์ — แทนที่อักขระด้วยตัวเอง
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 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การเข้ารหัสไฟล์และ API Response ใน JavaScript
ในโค้ด production การเข้ารหัส Base64 มักนำไปใช้กับไฟล์ที่กำลังส่งและ response จาก API ภายนอกที่ส่งเนื้อหาไบนารี รูปแบบจะแตกต่างกันระหว่างเบราว์เซอร์และ Node.js และข้อมูลไบนารีต้องการความใส่ใจเป็นพิเศษ
เบราว์เซอร์ — เข้ารหัสไฟล์จาก element input
// 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)
}
})ดึงข้อมูลไบนารีที่เข้ารหัส Base64 จาก API
// 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}`)เมื่อคุณแค่ต้องการตรวจสอบ response ที่เข้ารหัสระหว่าง debug API โดยไม่ต้องตั้ง script ให้วางค่า Base64 โดยตรงใน Base64 Encoder — ถอดรหัสด้วยเช่นกัน พร้อม output ทันที มีประโยชน์สำหรับตรวจสอบ GitHub API response, JWT payload และลายเซ็น webhook
การเข้ารหัส Base64 จาก Command-Line ใน Node.js และ Shell
สำหรับ script CI/CD, Makefile target หรือ debug ครั้งเดียว คุณแทบไม่ต้องการ script เต็ม ทั้งเครื่องมือระบบและ Node.js one-liner ครอบคลุมกรณีส่วนใหญ่ข้ามแพลตฟอร์ม
# ── 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=="base64 ตัดบรรทัด output ที่ 76 อักขระโดยค่าเริ่มต้น สิ่งนี้ทำลายการแยกวิเคราะห์ downstream เพิ่ม -b 0 (macOS) หรือ --wrap=0 (Linux) เสมอเมื่อต้องการผลลัพธ์บรรทัดเดียว — เช่น เมื่อเขียนลงในตัวแปร environment หรือ field ของ configทางเลือกประสิทธิภาพสูง: js-base64
API ในตัวเพียงพอสำหรับกรณีการใช้งานส่วนใหญ่ เหตุผลหลักในการใช้ library คือความสม่ำเสมอ ข้ามสภาพแวดล้อม: หากคุณส่ง package ที่ทำงานทั้งในเบราว์เซอร์และ Node.js การใช้ Buffer ต้องการทั้งการตรวจจับสภาพแวดล้อม หรือการตั้งค่า bundler ในขณะที่ btoa() ต้องการ Unicode workaround js-base64 (100M+ downloads ต่อสัปดาห์บน npm) จัดการทั้งสองแบบโปร่งใส
npm install js-base64 # or pnpm add js-base64
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ภายใต้ฝากระโปรง, js-base64 ใช้ Buffer แบบ native เมื่อมีและ fallback เป็น pure-JS implementation ในเบราว์เซอร์ เร็วกว่าวิธี TextEncoder+btoa 2–3 เท่าสำหรับ Unicode string ขนาดใหญ่ และ API แบบสมมาตร ( toBase64 / fromBase64) ขจัดภาระทางความคิดในการจำ ทิศทางของ btoa และ atob
การเข้ารหัสไฟล์ไบนารีขนาดใหญ่ด้วย Node.js Streams
เมื่อคุณต้องเข้ารหัสไฟล์ขนาดใหญ่กว่า ~50 MB การโหลดไฟล์ทั้งหมดเข้าหน่วยความจำด้วย readFileSync() กลายเป็นปัญหา Node.js stream ช่วยให้คุณประมวลผลข้อมูลเป็น chunk — แต่การเข้ารหัส Base64 มีข้อจำกัด: คุณต้องป้อน ข้อมูลให้ encoder เป็นพหุคูณของ 3 byte เพื่อหลีกเลี่ยง padding ที่ผิดที่ขอบ chunk
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')= ที่ไม่ถูกต้องตรงกลาง output ตัวอย่างใช้ 3 * 1024 * 256 = 786,432 byte (768 KB) — ปรับ highWaterMark ตามงบประมาณหน่วยความจำของคุณ สำหรับไฟล์ขนาดต่ำกว่า 50 MB, readFile() + Buffer.toString('base64') ง่ายกว่าและเร็วพอข้อผิดพลาดทั่วไป
ฉันได้ตรวจสอบ JavaScript codebase มากมายที่มีการเข้ารหัส Base64 และข้อผิดพลาดสี่อย่าง นี้ปรากฏอย่างสม่ำเสมอ — มักไม่ถูกค้นพบจนกว่าอักขระ non-ASCII หรือไฟล์ไบนารีจะถึง เส้นทางการเข้ารหัสใน production
ข้อผิดพลาดที่ 1 — ส่ง Unicode ตรงๆ ให้ btoa()
ปัญหา: btoa() รับเฉพาะอักขระที่มี code point 0–255 อักขระอย่าง ñ, emoji หรืออักษรภาพ CJK ทำให้เกิด DOMException ทันที วิธีแก้: เข้ารหัสด้วย TextEncoder ก่อน หรือใช้ Buffer.from(text, 'utf8').toString('base64') ใน Node.js
// ❌ 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('สุดา มีสุข')
// 4Liq4Lin4Li04LiX4Lip4LiX4LmM4LiXข้อผิดพลาดที่ 2 — ลืมคืน padding ก่อน atob()
ปัญหา: Base64 URL-safe ลบ padding = ออก การส่ง string ที่ลบ padding แล้วตรงๆ ให้ atob()ให้ output ที่ผิดหรือ throw ขึ้นอยู่กับความยาว string วิธีแก้: คืน + และ / และเพิ่ม padding กลับในจำนวนที่ถูกต้อง ก่อนเรียก atob()
// ❌ 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"}ข้อผิดพลาดที่ 3 — ต่อ chunk ที่เข้ารหัสแล้วแทนที่จะเป็น buffer ดิบ
ปัญหา: การเรียก btoa() หรือ .toString('base64') แต่ละครั้งเพิ่ม padding ของตัวเอง การต่อ string Base64 สองส่วนที่มี padding แล้วให้ output ที่ไม่ถูกต้อง เพราะ padding ควรอยู่ที่ท้ายสุดเท่านั้น วิธีแก้: ต่อข้อมูลดิบก่อนเข้ารหัส
// ❌ 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ข้อผิดพลาดที่ 4 — ใช้ response.text() เพื่ออ่านข้อมูล API ไบนารีก่อนเข้ารหัส
ปัญหา: response.text() แปล byte ดิบเป็น UTF-8 และ แทนที่ sequence byte ที่ไม่รู้จักด้วยอักขระแทนที่ U+FFFD เนื้อหาไบนารีใดๆ — รูปภาพ, PDF, เสียง — ถูกทำลายอย่างเงียบๆ ก่อนถึง btoa() วิธีแก้: ใช้ response.arrayBuffer() เพื่อรับ byte ดิบ
// ❌ 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วิธี Base64 JavaScript — เปรียบเทียบอย่างรวดเร็ว
| วิธี | Unicode | ข้อมูลไบนารี | URL-safe | สภาพแวดล้อม | ต้องติดตั้ง |
|---|---|---|---|---|---|
| btoa() / atob() | ❌ Latin-1 | ❌ ต้องการ workaround | ❌ แทนที่ด้วยตัวเอง | Browser, Node 16+, Bun, Deno | ไม่ |
| TextEncoder + btoa() | ✅ UTF-8 | ✅ ผ่าน Uint8Array | ❌ แทนที่ด้วยตัวเอง | Browser, Node 16+, Deno | ไม่ |
| Buffer.from().toString() | ✅ utf8 | ✅ native | ✅ base64url (Node 18+) | Node.js, Bun | ไม่ |
| Uint8Array.toBase64() (TC39) | ✅ ไบนารี | ✅ native | ✅ ตัวเลือก alphabet | Chrome 130+, Node 22+ | ไม่ |
| js-base64 | ✅ เสมอ | ✅ Uint8Array | ✅ ในตัว | ทุกสภาพแวดล้อม | npm install |
เลือก btoa() เฉพาะเมื่อ input พิสูจน์ได้ว่า เป็น ASCII เท่านั้น — hex digest, ID ตัวเลข หรือ string Latin-1 ที่ตรวจสอบล่วงหน้าแล้ว สำหรับข้อความที่ผู้ใช้ป้อนในเบราว์เซอร์ ใช้ TextEncoder + btoa() สำหรับโค้ด Node.js ฝั่ง server ทั้งหมด Buffer คือค่าเริ่มต้นที่ถูกต้อง สำหรับ library ที่ต้องทำงานในทั้งสองสภาพแวดล้อมโดยไม่ต้องตั้งค่า bundler js-base64 ขจัด edge case ทั้งหมด
คำถามที่พบบ่อย
เครื่องมือที่เกี่ยวข้อง
สำหรับการเข้ารหัสหรือถอดรหัสด้วยคลิกเดียวโดยไม่ต้องเขียนโค้ด วาง string หรือไบนารี ของคุณโดยตรงใน Base64 Encoder — จัดการทั้งโหมดมาตรฐานและ URL-safe ทันทีในเบราว์เซอร์ของคุณ
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.
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.