فك ترميز Base64 في JavaScript — atob والـ Buffer
استخدم فك ترميز Base64 أونلاين المجاني مباشرةً في متصفحك — لا حاجة للتثبيت.
جرّب فك ترميز Base64 أونلاين أونلاين ←حين أحاول تصحيح مشكلة مصادقة في الإنتاج، أول ما أتوجه إليه هو أداة فك تشفير Base64 — حمولات JWT، وتواقيع webhook، وقيم الإعداد المشفّرة كلها مخبّأة داخل سلاسل Base64. يوفر JavaScript أسلوبَين أصليَّين رئيسيَّين لفك ترميز Base64: atob() (المتصفح + Node.js 16+) و Buffer.from(encoded, 'base64').toString() (Node.js) — وسلوكهما يختلف اختلافاً كبيراً حين يحتوي النص الأصلي على محارف Unicode. للحصول على فك ترميز سريع دون كتابة أي كود، أداة فك تشفير Base64 في ToolDeck تُعالج ذلك فوراً في متصفحك. يغطي هذا الدليل كلتا البيئتين — Node.js 16+ والمتصفحات الحديثة (Chrome 80+، Firefox 75+، Safari 14+) — مع أمثلة جاهزة للإنتاج: استعادة UTF-8، والمتغيرات الآمنة للروابط، وفك ترميز JWT، والملفات، واستجابات API، وتدفقات Node.js، والأخطاء الأربعة التي تُنتج مخرجات مشوهة باستمرار في قواعد الكود الحقيقية.
- ✓الدالة atob(encoded) متاحة في المتصفح وفي Node.js 16+ بشكل افتراضي، لكنها تُعيد سلسلة ثنائية — استخدم TextDecoder لاستعادة نص UTF-8 من أي محتوى يتجاوز نطاق ASCII.
- ✓الدالة Buffer.from(encoded, "base64").toString("utf8") هي الأسلوب المعتمد في Node.js وتتعامل مع UTF-8 تلقائياً دون خطوات إضافية.
- ✓يستبدل Base64 الآمن للروابط (URL-safe) الرمز + بـ - والرمز / بـ _ ويحذف حشو = — أعد هذه الرموز قبل استدعاء atob()، أو استخدم Buffer.from(encoded, "base64url").toString() في Node.js 18+.
- ✓احذف المسافات والأسطر الجديدة قبل فك الترميز — تُغلّف واجهة برمجة GitHub Contents API ومحركات MIME الكثيرة مخرجات Base64 عند 60-76 حرفاً لكل سطر.
- ✓الدالة Uint8Array.prototype.fromBase64() (TC39 المرحلة 3) متاحة في Node.js 22+ وChrome 130+ وستوحّد كلا البيئتين مستقبلاً.
ما هو فك ترميز Base64؟
فك ترميز Base64 هو العملية العكسية للترميز — يحوّل التمثيل الـ ASCII المكوّن من 64 حرفاً إلى البيانات الثنائية الأصلية أو النص. كل 4 محارف Base64 تُعاد تحويلها إلى 3 بايتات بالضبط. محارف الحشو = في نهاية السلسلة المشفّرة تُخبر المفكك بعدد البايتات الإضافية التي أُضيفت لإكمال المجموعة الأخيرة من 3 بايتات.
Base64 ليس تشفيراً — العملية قابلة للعكس تماماً من قِبَل أي شخص يملك السلسلة المشفّرة. الغرض منه هو أمان النقل: البروتوكولات وتنسيقات التخزين المصممة لنص ASCII ذي 7 بتات لا تستطيع التعامل مع بايتات ثنائية عشوائية، وBase64 يجسر هذه الفجوة. تشمل سيناريوهات فك ترميز JavaScript الشائعة: فحص حمولات JWT، وفك ضغط إعدادات JSON المشفّرة بـ Base64 من متغيرات البيئة، واستخراج محتوى الملفات الثنائية من REST APIs، وفك ترميز data URIs في المتصفح.
deploy-bot:sk-prod-a7f2c91e4b3d8
ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=
الدالة 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 الواجهة المعتمدة لجميع العمليات الثنائية بما في ذلك فك ترميز Base64. يتعامل مع UTF-8 بشكل أصلي، ويُعيد Buffer حقيقياً (آمن ثنائياً)، ومنذ Node.js 18 يدعم اختصار الترميز 'base64url' للمتغيرات الآمنة للروابط.
فك ترميز متغير بيئة يحتوي إعدادات
// 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 — مرجع المعاملات
مرجع سريع لمعاملات واجهتي فك الترميز الأصليتين الرئيسيتين، مُنسَّق للاستخدام كمرجع عند كتابة الكود أو مراجعته.
atob(encodedData)
| المعامل | النوع | مطلوب | الوصف |
|---|---|---|---|
| encodedData | string | نعم | سلسلة Base64 قياسية تستخدم محارف +، /، =. المتغيرات الآمنة للروابط (- و_) تُلقي InvalidCharacterError. المسافات البيضاء غير مسموح بها. |
Buffer.from(input, inputEncoding) / .toString(outputEncoding)
| المعامل | النوع | الافتراضي | الوصف |
|---|---|---|---|
| input | string | Buffer | TypedArray | ArrayBuffer | مطلوب | السلسلة المشفّرة بـ Base64 المراد فكّها، أو buffer يحتوي البايتات المشفّرة. |
| inputEncoding | BufferEncoding | "utf8" | اضبطه على "base64" للـ Base64 القياسي (RFC 4648 §4)، أو "base64url" للـ 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() كمعامل ثالث. |
Base64 الآمن للروابط — فك ترميز JWTs ومعاملات URL
تستخدم JWTs الـ Base64 الآمن للروابط (RFC 4648 §5) للقطاعات الثلاث. يستبدل 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 خارجية تُسلّم المحتوى بصيغة مشفّرة. كلا السيناريوين لهما مشاكل مهمة تتعلق بالمسافات البيضاء ومخرجات الثنائي مقابل النص. إذا كنت تريد فقط فحص استجابة مشفّرة أثناء تصحيح الأخطاء، الصقها مباشرة في أداة فك تشفير Base64 — تتعامل مع الوضعين القياسي والآمن للروابط بمخرجات فورية.
فك ترميز المحتوى من 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 والشل
لسكريبتات 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 معاً دون إعداد bundler، 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.
// ✅ 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) // Алексей Иванов ✓
// ❌ atob() returns the raw UTF-8 bytes as a Latin-1 string const encoded = '0JDQu9C10LrRgdC10Lkg0JjQstCw0L3QvtCy' const decoded = atob(encoded) console.log(decoded) // "Алексей Р˜РІР°РЅРѕРІ" ← wrong
الخطأ 2 — تمرير Base64 الآمن للروابط مباشرة إلى atob()
المشكلة: قطاعات JWT تستخدم - و _ بدلاً من + و /، بدون حشو. قد تُعيد atob() نتيجة خاطئة أو تُلقي استثناءً. الحل: استعد المحارف القياسية وأضف الحشو أولاً.
// ✅ 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"} ✓// ❌ URL-safe JWT segment passed directly — unreliable const jwtPayload = 'eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2UifQ' const decoded = atob(jwtPayload) // May produce wrong result or throw
الخطأ 3 — عدم حذف الأسطر الجديدة من Base64 المُغلَّف في أسطر
المشكلة: تُغلّف GitHub Contents API ومشفّرات MIME مخرجات Base64 عند 60–76 محرفاً لكل سطر. تُلقي atob() خطأ InvalidCharacterError على محارف \n. الحل: احذف جميع المسافات البيضاء قبل فك الترميز.
// ✅ Strip newlines (and any other whitespace) before decoding const data = await res.json() const clean = data.content.replace(/\s/g, '') const decoded = atob(clean) // ✓
// ❌ GitHub API content field contains embedded newlines const data = await res.json() const decoded = atob(data.content) // ❌ throws InvalidCharacterError
الخطأ 4 — استدعاء .toString() على محتوى ثنائي مفكوك
المشكلة: حين تكون البيانات الأصلية ثنائية (صور، PDFs، صوت)، يستبدل .toString('utf8') تسلسلات البايتات غير المعروفة بـ U+FFFD، مما يُفسد المخرجات بصمت. الحل: احتفظ بالنتيجة كـ Buffer — لا تحوّله إلى سلسلة نصية.
// ✅ 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// ❌ .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طرق فك ترميز Base64 في JavaScript — مقارنة سريعة
| الطريقة | مخرجات UTF-8 | مخرجات ثنائية | آمن للروابط | البيئات | يتطلب تثبيت |
|---|---|---|---|---|---|
| atob() | ❌ تحتاج TextDecoder | ✅ سلسلة ثنائية | ❌ استعادة يدوية | متصفح، Node 16+، Bun، Deno | لا |
| TextDecoder + atob() | ✅ UTF-8 | ✅ عبر Uint8Array | ❌ استعادة يدوية | متصفح، 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 — تتعامل مع الوضعين القياسي والآمن للروابط بمخرجات فورية في متصفحك.
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.