Base64 Decode в JavaScript: atob() и Buffer
Используйте бесплатный Base64 Decode Online прямо в браузере — установка не требуется.
Попробовать Base64 Decode Online онлайн →Когда я отлаживаю проблему с аутентификацией в продакшене, первое, за что я берусь, — это Base64 decoder: JWT-пэйлоады, подписи вебхуков и закодированные конфигурационные значения прячутся внутри Base64-строк. JavaScript предоставляет два встроенных подхода к base64-декодированию: atob() (браузер + Node.js 16+) и Buffer.from(encoded, 'base64').toString() (Node.js) — и они ведут себя очень по-разному, когда исходные данные содержат символы Unicode. Для быстрого однократного декодирования без написания кода Base64 Decoder от ToolDeck справится мгновенно прямо в браузере. Это руководство охватывает оба окружения — Node.js 16+ и современные браузеры (Chrome 80+, Firefox 75+, Safari 14+) — с готовыми к продакшену примерами: восстановление UTF-8, URL-безопасные варианты, декодирование JWT, файлов, ответов API, потоков Node.js и четыре ошибки, которые стабильно приводят к искажённому выводу в реальных проектах.
- ✓atob(encoded) встроен в браузер и доступен в Node.js 16+ глобально, но возвращает бинарную строку — используйте TextDecoder для восстановления UTF-8 текста из любого содержимого выше ASCII.
- ✓Buffer.from(encoded, "base64").toString("utf8") — идиоматический подход в Node.js, обрабатывающий UTF-8 автоматически без дополнительных шагов.
- ✓URL-безопасный Base64 (используемый в JWT) заменяет + на -, / на _ и убирает паддинг =. Восстановите их перед вызовом atob() или используйте Buffer.from(encoded, "base64url").toString() в Node.js 18+.
- ✓Удаляйте пробелы и переносы строк перед декодированием — GitHub Contents API и многие MIME-энкодеры переносят вывод Base64 каждые 60–76 символов.
- ✓Uint8Array.prototype.fromBase64() (TC39 Stage 3) уже доступен в Node.js 22+ и Chrome 130+ и в итоге унифицирует оба окружения.
Что такое декодирование Base64?
Декодирование Base64 — это обратная операция по отношению к кодированию: она преобразует 64-символьное ASCII-представление обратно в исходные бинарные данные или текст. Каждые 4 символа Base64 соответствуют ровно 3 байтам. Символы = в конце закодированной строки сообщают декодеру, сколько дополнительных байт было добавлено для завершения последней 3-байтовой группы.
Base64 — это не шифрование: операция полностью обратима для любого, у кого есть закодированная строка. Его назначение — транспортная совместимость: протоколы и форматы хранения, рассчитанные на 7-битный ASCII-текст, не могут обрабатывать произвольные бинарные байты, и Base64 устраняет этот разрыв. Типичные сценарии декодирования в JavaScript включают инспекцию JWT-пэйлоадов, распаковку Base64-закодированных JSON-конфигов из переменных окружения, извлечение содержимого бинарных файлов из REST API и декодирование data URI в браузере.
ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=
deploy-bot:sk-prod-a7f2c91e4b3d8
atob() — встроенная функция декодирования для браузеров
atob() (ASCII-to-binary) доступен в браузерах начиная с IE10 и стал глобальной функцией в Node.js 16.0 в рамках инициативы WinterCG по совместимости. Он также работает нативно в Deno, Bun и Cloudflare Workers — без импорта.
Функция возвращает бинарную строку: JavaScript-строку, в которой каждый символ имеет кодовую точку, равную одному значению сырого байта (0–255). Это важно: если исходные данные были UTF-8 текстом, содержащим символы выше U+007F (буквы с диакритикой, кириллица, CJK, эмодзи), возвращаемая строка представляет собой сырую последовательность байт, а не читаемый текст. Используйте TextDecoder, чтобы восстановить его (подробнее в следующем разделе).
Минимальный рабочий пример
// 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Проверка корректности восстановления данных
// 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 — той же спецификации, которая регулирует Fetch, URL и crypto в небраузерных средах выполнения. Они ведут себя одинаково в Node.js 16+, Bun, Deno и Cloudflare Workers.Восстановление UTF-8 текста после декодирования
Самая распространённая ловушка с atob() — непонимание типа возвращаемого значения. Когда исходный текст был закодирован в UTF-8 перед Base64, atob() возвращает Latin-1 бинарную строку, а не читаемый текст:
// 'Алексей Иванов' 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 для интерпретации этих сырых байт как UTF-8:
Подход с TextDecoder — безопасен для любого Unicode-вывода
// 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: 250Buffer.from(encoded, 'base64').toString('utf8'). Он автоматически интерпретирует декодированные байты как UTF-8 и работает быстрее для больших входных данных.Buffer.from() в Node.js — полное руководство по декодированию
В Node.js Buffer является идиоматическим API для всех бинарных операций, включая декодирование Base64. Он обрабатывает UTF-8 нативно, возвращает полноценный Buffer (безопасный для бинарных данных), а начиная с Node.js 18 поддерживает сокращение 'base64url' для URL-безопасных вариантов.
Декодирование конфига из переменной окружения
// 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-файла
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Асинхронное декодирование с обработкой ошибок
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`)Функции декодирования Base64 — справочник параметров
Краткий справочник параметров двух основных нативных API декодирования для использования при написании и проверке кода.
atob(encodedData)
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
| encodedData | string | Да | Стандартная Base64-строка, использующая символы +, /, =. URL-безопасные варианты (-, _) вызывают InvalidCharacterError. Пробелы не допускаются. |
Buffer.from(input, inputEncoding) / .toString(outputEncoding)
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| input | string | Buffer | TypedArray | ArrayBuffer | обязателен | Base64-закодированная строка для декодирования или буфер с закодированными байтами. |
| inputEncoding | BufferEncoding | "utf8" | Установите "base64" для стандартного Base64 (RFC 4648 §4) или "base64url" для URL-безопасного Base64 (RFC 4648 §5, Node.js 18+). |
| outputEncoding | string | "utf8" | Кодировка для вывода .toString(). Используйте "utf8" для читаемого текста, "binary" для Latin-1 бинарной строки, совместимой с выводом atob(). |
| start | integer | 0 | Смещение байта внутри декодированного Buffer, с которого начинать чтение. Передаётся в .toString() как второй аргумент. |
| end | integer | buf.length | Смещение байта для остановки чтения (не включительно). Передаётся в .toString() как третий аргумент. |
URL-безопасный Base64 — декодирование JWT и URL-параметров
JWT используют URL-безопасный Base64 (RFC 4648 §5) для всех трёх сегментов. URL-безопасный Base64 заменяет + на - и / на _, а также убирает завершающий = паддинг. Передача этого напрямую в atob() без восстановления даёт некорректный вывод или исключение.
Браузер — восстановление символов и паддинга перед декодированием
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_3a7f91c2Node.js 18+ — нативная кодировка 'base64url'
// 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Декодирование Base64 из файлов и ответов API
В продакшен-коде декодирование Base64 чаще всего происходит при работе с внешними API, которые возвращают контент в закодированном виде. В обоих сценариях есть важные нюансы вокруг пробелов и бинарного vs текстового вывода. Если вам просто нужно осмотреть закодированный ответ при отладке, вставьте его напрямую в Base64 Decoder — он моментально обрабатывает стандартный и URL-безопасный режимы.
Декодирование содержимого из GitHub Contents API
// 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}`)Декодирование Base64-закодированного бинарного файла из API (браузер)
// 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')!)Декодирование Base64 через командную строку в Node.js и Shell
Для CI/CD-скриптов, отладочных сессий или разовых задач декодирования утилиты командной строки и однострочники Node.js быстрее полноценного скрипта. Обратите внимание, что имя флага различается на macOS и Linux.
# ── 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"}base64 использует -D для декодирования (заглавная D), тогда как Linux использует -d (строчная). Это незаметно ломает CI-скрипты — используйте однострочник Node.js, когда целевая платформа не гарантированно является Linux.Высокопроизводительная альтернатива: js-base64
Главная причина использовать библиотеку — кросс-средовая согласованность. Если вы поставляете пакет, работающий как в браузере, так и в Node.js без настройки бандлера, Buffer требует определения среды, а atob() требует обходного пути через TextDecoder. js-base64 (более 100 млн еженедельных загрузок npm) прозрачно обрабатывает оба варианта.
npm install js-base64 # or pnpm add js-base64
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Вывод в терминал с подсветкой синтаксиса
При написании CLI-инструментов отладки или скриптов инспекции простой console.log сложно читать для больших JSON-пэйлоадов. chalk (самый скачиваемый npm-пакет для раскраски терминала) в сочетании с декодированием Base64 даёт читаемый, легко просматриваемый вывод — полезен для инспекции JWT, отладки ответов API и аудита конфигов.
npm install chalk # chalk v5+ is ESM-only — use import, not require
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Декодирование больших Base64-файлов с помощью потоков Node.js
Когда Base64-закодированный файл превышает ~50 МБ, загрузка его целиком в память с помощью readFileSync() становится проблемой. Потоки Node.js позволяют декодировать данные по частям — но Base64 требует кратных 4 символам чанков (каждая 4-символьная группа декодируется ровно в 3 байта) во избежание ошибок паддинга на границах чанков.
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')4 × 1024 × 192 = 786 432 символа (768 КБ). Для файлов до 50 МБ readFile() + Buffer.from(content.trim(), 'base64') проще и достаточно быстро.Распространённые ошибки
Я видел эти четыре ошибки в JavaScript-кодовых базах снова и снова — они, как правило, остаются незамеченными до тех пор, пока не ASCII символ или перенесённый ответ API не достигает пути декодирования в продакшене.
Ошибка 1 — Использование atob() без TextDecoder для UTF-8 контента
Проблема: atob() возвращает бинарную строку, где каждый символ — это одно значение сырого байта. Многобайтовые UTF-8 последовательности (кириллица, CJK, буквы с диакритикой) отображаются как искажённые Latin-1 символы. Решение: оберните вывод в TextDecoder.
// ❌ 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-безопасного Base64 напрямую в atob()
Проблема: JWT-сегменты используют - и _ вместо + и /, без паддинга. atob() может вернуть неверные данные или выбросить исключение. Решение: сначала восстановите стандартные символы и добавьте паддинг.
// ❌ 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 — Не удалять переносы строк из перенесённого Base64
Проблема: GitHub Contents API и MIME-энкодеры переносят вывод Base64 каждые 60–76 символов. atob() выбрасывает InvalidCharacterError на символах \n. Решение: удалите все пробелы перед декодированием.
// ❌ 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() на декодированном бинарном контенте
Проблема: Когда исходные данные являются бинарными (изображения, PDF, аудио), вызов .toString('utf8') заменяет нераспознанные байтовые последовательности на U+FFFD, незаметно повреждая вывод. Решение: оставляйте результат как Buffer — не преобразовывайте в строку.
// ❌ .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Методы декодирования Base64 в JavaScript — быстрое сравнение
| Метод | UTF-8 вывод | Бинарный вывод | URL-безопасный | Окружения | Требует установки |
|---|---|---|---|---|---|
| atob() | ❌ нужен TextDecoder | ✅ бинарная строка | ❌ ручное восстановление | 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 | ✅ нативный | ✅ опция alphabet | Chrome 130+, Node 22+ | Нет |
| js-base64 | ✅ всегда | ✅ Uint8Array | ✅ встроен | Универсально | npm install |
Используйте atob() только когда декодируемое содержимое гарантированно является ASCII-текстом. Для любого пользовательского или многоязычного текста в браузере используйте TextDecoder + atob(). Для серверного кода Node.js Buffer — правильный выбор по умолчанию: он обрабатывает UTF-8 автоматически и сохраняет бинарные данные нетронутыми. Для кросс-средовых библиотек js-base64 устраняет все граничные случаи.
Часто задаваемые вопросы
Связанные инструменты
Для декодирования в один клик без написания кода вставьте вашу Base64-строку напрямую в Base64 Decoder — он обрабатывает стандартный и 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.