JavaScript Base64 エンコードガイド:btoa() と Buffer の使い方
無料の Base64エンコーダー をブラウザで直接使用 — インストール不要。
Base64エンコーダー をオンラインで試す →CSS の data URI に画像を埋め込んだり、HTTP Authorization ヘッダーに認証情報を渡したり、 バイナリ証明書を環境変数に保存したりする際、ブラウザと Node.js の両方で JavaScript データを 確実に Base64 エンコードする必要があります。JavaScript には 2 つの異なる組み込み API があります:btoa() はブラウザ環境用(Node.js 16+ でも利用可能)、Buffer.from() は Node.js 用です — それぞれ Unicode、バイナリデータ、URL 安全性に関して異なる制約があります。コードを書かずに素早くエンコードするには、 ToolDeck's Base64 Encoder がブラウザで即座に処理します。このガイドでは、両環境における本番対応の例を網羅します:Unicode 処理、URL セーフバリアント、ファイルと API レスポンスのエンコード、CLI の使用法、そして実際のコードベースで一貫して発生する 4 つのミスについて説明します。
- ✓btoa() はブラウザネイティブで Node.js 16+ でもグローバルに使用できますが、Latin-1(コードポイント 0–255)のみ受け付けます — Unicode 入力は DOMException をスローします
- ✓Buffer.from(text, "utf8").toString("base64") は Node.js の同等メソッドで、追加の手順なしに Unicode をネイティブで処理します
- ✓URL セーフ Base64 は + を -、/ を _ に置換し、= パディングを除去します — Node.js 18+ では Buffer.from().toString("base64url") で一行で実現できます
- ✓バイナリデータ(ArrayBuffer、Uint8Array、ファイル)には Node.js では Buffer を、ブラウザでは arrayBuffer() + Uint8Array アプローチを使用してください — response.text() は絶対に使用しないでください
- ✓Uint8Array.prototype.toBase64()(TC39 Stage 3)は Node.js 22+ と Chrome 130+ ですでに利用可能で、両環境を統一します
Base64 エンコードとは?
Base64 は任意のバイナリデータを 64 個の印刷可能な ASCII 文字から構成される文字列に変換します: A–Z、a–z、0–9、+、および /。入力の 3 バイトごとにちょうど 4 つの Base64 文字にマッピングされます。 入力長が 3 の倍数でない場合、1 つまたは 2 つの = パディング文字が追加されます。 エンコード後の出力は元のデータより約 33% 大きくなります。
Base64 は暗号化ではありません — 機密性は提供されません。 エンコードされた文字列を持っている人であれば誰でも、1 回の関数呼び出しでデコードできます。 その目的はトランスポートの安全性です:多くのプロトコルやストレージ形式は 7 ビット ASCII テキスト用に設計されており、 任意のバイナリバイトを扱えません。Base64 がそのギャップを埋めます。 JavaScript での一般的なユースケースには、アセットをインライン化するための data URI、 HTTP Basic Auth ヘッダー、JWT トークンセグメント、メール MIME 添付ファイル、JSON API でのバイナリ blob の保存が含まれます。
deploy-bot:sk-prod-a7f2c91e4b3d8
ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=
btoa() — ブラウザネイティブのエンコード関数
btoa()(binary-to-ASCII)は IE10 からブラウザで利用可能で、 WinterCG 互換性イニシアチブの一環として Node.js 16.0 でグローバル関数になりました。 Deno、Bun、Cloudflare Workers でもネイティブに動作します。インポートは不要です。
この関数は文字列引数を 1 つ受け取り、その Base64 エンコード形式を返します。 対称的な逆関数 atob()(ASCII-to-binary)でデコードできます。 両方とも同期処理で、入力サイズに対してメモリ使用量は定数です。
最小動作例
// 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 の一部です — ブラウザ以外のランタイムにおける Fetch、URL、crypto を管理する同じ仕様です。 Node.js 16+、Bun、Deno、Cloudflare Workers で同一の動作をします。Unicode と非 ASCII 文字の処理
btoa() の最も一般的な落とし穴は、 その厳格な Latin-1 境界です。U+00FF を超えるコードポイントを持つ文字は即座に例外を引き起こします:
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正しいアプローチは、まず文字列を UTF-8 バイトにエンコードし、 次にそれらのバイトを Base64 エンコードすることです。 JavaScript にはまさにこの目的のために TextEncoder が用意されています:
TextEncoder アプローチ — 任意の Unicode 入力に対して安全
// 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)
// 56K644GX44G/77ya55Sw5Lit5aSq6YOO4oCU5p2x5Lqs5YCJ5bqr44CB5pWZ6K+V77yaMjUw
console.log(decoded === orderNote) // trueBuffer.from(text, 'utf8').toString('base64') を使用してください。 Unicode をネイティブで処理し、大きな文字列では高速です。Node.js の Buffer.from() — 例を交えた完全ガイド
Node.js では、Buffer がエンコード変換を含むすべての バイナリデータ操作の慣用的な API です。TextEncoder より数年早く登場し、 サーバーサイドコードの推奨手段であり続けています。 btoa() に対する主な利点:ネイティブ UTF-8 サポート、 バイナリデータ処理、Node.js 18 以降で利用可能な 'base64url' エンコードショートカット。
基本的なテストのエンコードとデコード
// 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エラーハンドリングを含む非同期ファイルエンコード
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`)JavaScript Base64 関数 — パラメータリファレンス
Python の base64 モジュールとは異なり、 JavaScript には単一の統一された Base64 関数がありません。 使用する API は対象環境によって異なります。ここにすべてのネイティブアプローチの完全リファレンスを示します:
| 関数 | 入力タイプ | Unicode | URL セーフ | 利用可能な環境 |
|---|---|---|---|---|
| btoa(string) | string (Latin-1) | ❌ U+00FF を超えるとスロー | ❌ 手動置換 | Browser, Node 16+, Bun, Deno |
| atob(string) | Base64 string | ❌ バイナリ文字列を返す | ❌ 手動置換 | Browser, Node 16+, Bun, Deno |
| Buffer.from(src, enc) .toString(enc) | string | Buffer | Uint8Array | ✅ utf8 エンコード | ✅ Node 18+ の base64url | Node.js, Bun |
| TextEncoder().encode(str) + btoa() | string(任意の Unicode) | ✅ UTF-8 バイト経由 | ❌ 手動置換 | Browser, Node 16+, Deno |
| Uint8Array.toBase64() (TC39) | Uint8Array | ✅ バイナリ | ✅ omitPadding + alphabet | Chrome 130+, Node 22+ |
Buffer.from(src, enc).toString(enc) シグネチャは Base64 に関連するいくつかのエンコード値を受け付けます:
URL セーフ Base64 — JWT、URL、ファイル名のエンコード
標準 Base64 は + と / を使用しますが、これらは URL で予約されています — + はクエリ文字列でスペースとしてデコードされ、 / はパス区切り文字です。JWT、URL パラメータ、 ファイル名、Cookie の値はすべて URL セーフバリアントが必要です:+ → -、 / → _、末尾の = を削除。
ブラウザ — 手動文字置換
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+ — ネイティブ 'base64url' エンコード
// 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) // editorJavaScript でファイルと API レスポンスをエンコード
本番コードでは、Base64 エンコードは送信されるファイルと、バイナリコンテンツを返す外部 API からのレスポンスに最も頻繁に適用されます。 パターンはブラウザと Node.js で異なり、バイナリデータには特別な注意が必要です。
ブラウザ — 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)
}
})API から Base64 エンコードされたバイナリを取得
// 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}`)API デバッグ中にエンコードされたレスポンスをスクリプトなしで検査したい場合は、 Base64 の値を Base64 Encoder に直接貼り付けてください — デコードも対応しており、即座に出力されます。 GitHub API レスポンス、JWT ペイロード、webhook シグネチャの検査に便利です。
Node.js とシェルでのコマンドライン Base64 エンコード
CI/CD スクリプト、Makefile ターゲット、または一時的なデバッグには、フルスクリプトはほとんど必要ありません。 システムツールと Node.js のワンライナーでクロスプラットフォームのほとんどのケースをカバーできます。
# ── 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 はデフォルトで 76 文字で出力を折り返します。 これにより下流のパースが壊れます。環境変数やコンフィグフィールドへの書き込みなど、 単一行の結果が必要な場合は、必ず -b 0(macOS)または --wrap=0(Linux)を追加してください。高性能な代替案:js-base64
組み込み API はほとんどのユースケースで十分です。ライブラリを使う主な理由はクロス環境の一貫性です: ブラウザと Node.js の両方で動作するパッケージを配布する場合、 Buffer を使うには環境検出かバンドラー設定が必要で、btoa() では Unicode の回避策が必要です。js-base64(npm 週次ダウンロード 1 億回超)は両方を透過的に処理します。
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 を使用し、 ブラウザでは純粋な JS 実装にフォールバックします。 大きな Unicode 文字列では TextEncoder+btoa アプローチより 2〜3 倍高速で、 対称的な API(toBase64 / fromBase64)により btoa と atob の方向を覚える認知的負担がなくなります。
Node.js ストリームを使った大きなバイナリファイルのエンコード
約 50 MB を超えるファイルをエンコードする必要がある場合、 readFileSync() でファイル全体をメモリにロードすることが問題になります。 Node.js ストリームを使えばデータをチャンクで処理できますが、Base64 エンコードには制約があります: チャンクの境界で不正なパディングが生じないよう、エンコーダには 3 バイトの倍数を入力する必要があります。
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')= パディングが入らないよう、チャンクサイズは 3 バイトの倍数にする必要があります。 例では 3 * 1024 * 256 = 786,432 バイト(768 KB)を使用しています — highWaterMark はメモリ予算に応じて調整してください。 50 MB 未満のファイルでは、readFile() + Buffer.toString('base64') の方がシンプルで十分高速です。よくあるミス
Base64 エンコードを含む多くの JavaScript コードベースをレビューしてきましたが、 これら 4 つのミスが一貫して見られます — 多くの場合、非 ASCII 文字またはバイナリファイルが 本番環境のエンコードパスに到達するまで発見されません。
ミス 1 — Unicode を btoa() に直接渡す
問題: btoa() はコードポイント 0–255 の文字のみ受け付けます。ñ、絵文字、CJK 漢字などの文字は即座に DOMException を引き起こします。 修正方法: 先に TextEncoder でエンコードするか、Node.js では Buffer.from(text, 'utf8').toString('base64') を使用してください。
// ❌ 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ミス 2 — atob() を呼ぶ前にパディングの復元を忘れる
問題: URL セーフ Base64 は = パディングを除去します。 パディングなしの文字列を atob() に直接渡すと、 文字列の長さによって不正な出力またはスローが発生します。 修正方法: 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 — 生のバッファではなくエンコードされたチャンクを連結する
問題: btoa() や .toString('base64') を呼び出すたびに、 独自のパディングが追加されます。2 つのパディング付き Base64 文字列を連結すると、 パディングは最後だけに属するべきであるため、無効な出力が生成されます。 修正方法: エンコードする前に生データを連結してください。
// ❌ 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() は生のバイトを UTF-8 として解釈し、 認識できないバイトシーケンスを置換文字 U+FFFD に置き換えます。 バイナリコンテンツ(画像、PDF、音声)は btoa() に到達する前にサイレントに破損します。 修正方法: 生のバイトを取得するには response.arrayBuffer() を使用してください。
// ❌ 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 Base64JavaScript Base64 メソッド — クイック比較
| メソッド | Unicode | バイナリデータ | URL セーフ | 利用可能な環境 | インストール要否 |
|---|---|---|---|---|---|
| btoa() / atob() | ❌ Latin-1 | ❌ 回避策が必要 | ❌ 手動置換 | Browser, Node 16+, Bun, Deno | 不要 |
| TextEncoder + btoa() | ✅ UTF-8 | ✅ Uint8Array 経由 | ❌ 手動置換 | Browser, Node 16+, Deno | 不要 |
| Buffer.from().toString() | ✅ utf8 | ✅ ネイティブ | ✅ base64url (Node 18+) | Node.js, Bun | 不要 |
| Uint8Array.toBase64() (TC39) | ✅ バイナリ | ✅ ネイティブ | ✅ alphabet オプション | Chrome 130+, Node 22+ | 不要 |
| js-base64 | ✅ 常に | ✅ Uint8Array | ✅ 組み込み | ユニバーサル | npm install |
入力が確実に ASCII のみの場合(16 進ダイジェスト、数値 ID、事前検証済みの Latin-1 文字列)にのみ btoa() を選択してください。 ブラウザでのユーザー提供テキストには TextEncoder + btoa() を使用してください。 すべての Node.js サーバーサイドコードでは、Buffer が適切なデフォルトです。 バンドラー設定なしで両環境で動作する必要があるライブラリには、 js-base64 がすべてのエッジケースを排除します。
よくある質問
関連ツール
コードを書かずにワンクリックでエンコードまたはデコードするには、文字列またはバイナリを Base64 Encoder に直接貼り付けてください — ブラウザで標準と URL セーフモードを即座に処理します。
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.