Base64 في JavaScript — btoa() وBuffer
استخدم مشفّر Base64 عبر الإنترنت المجاني مباشرةً في متصفحك — لا حاجة للتثبيت.
جرّب مشفّر Base64 عبر الإنترنت أونلاين ←عندما تضمّن صورة في CSS data URI، أو تمرر بيانات اعتماد في رأس HTTP Authorization، أو تخزّن شهادة ثنائية في متغير بيئة، تحتاج إلى ترميز Base64 لبيانات JavaScript بشكل موثوق عبر المتصفح وNode.js. يوفر JavaScript واجهتي برمجة تطبيقات مدمجتين مختلفتين:btoa() لبيئات المتصفح (متاحة أيضاً في Node.js 16+) وBuffer.from() لـ Node.js — كلٌّ منهما بقيود مختلفة حول Unicode والبيانات الثنائية وسلامة الروابط. لترميز سريع دون كتابة أي كود، مُرمِّز Base64 في ToolDeck يتعامل معه فوراً في المتصفح. يغطي هذا الدليل كلا البيئتين مع أمثلة جاهزة للإنتاج: معالجة Unicode، والمتغيرات الآمنة للروابط، وترميز الملفات واستجابات API، واستخدام CLI، والأخطاء الأربعة التي تسبب أخطاء باستمرار في قواعد الكود الحقيقية.
- ✓الدالة btoa() متاحة نصياً في المتصفح وفي Node.js 16+ بشكل عالمي، لكنها تقبل فقط Latin-1 (نقاط الكود 0–255) — إدخال Unicode يُطلق استثناء DOMException
- ✓الدالة Buffer.from(text, "utf8").toString("base64") هي المكافئ في Node.js وتعالج Unicode بشكل أصلي دون خطوات إضافية
- ✓Base64 الآمن للروابط يستبدل + بـ - و / بـ _ ويحذف حشو = — استخدم Buffer.from().toString("base64url") في Node.js 18+ للحصول على سطر واحد
- ✓للبيانات الثنائية (ArrayBuffer، Uint8Array، الملفات)، استخدم Buffer في Node.js أو نهج arrayBuffer() + Uint8Array في المتصفح — لا تستخدم response.text() أبداً
- ✓الدالة Uint8Array.prototype.toBase64() (TC39 المرحلة 3) متاحة بالفعل في Node.js 22+ وChrome 130+ وستوحد البيئتين
ما هو ترميز Base64؟
يحوّل Base64 البيانات الثنائية الاعتباطية إلى سلسلة مبنية من 64 حرفاً ASCII قابلاً للطباعة: A–Z، a–z، 0–9، +، و /. كل 3 بايت من الإدخال تُعيَّن إلى 4 أحرف Base64 بالضبط؛ إذا لم يكن طول الإدخال مضاعفاً للعدد 3، يُضاف حرف أو حرفا حشو =. الناتج المُرمَّز دائماً أكبر بنحو 33% من الأصل.
Base64 ليس تشفيراً — لا يوفر أي سرية. يمكن لأي شخص يمتلك السلسلة المُرمَّزة فك ترميزها باستدعاء دالة واحدة. غرضه هو سلامة النقل: كثير من البروتوكولات وصيغ التخزين صُممت لنص ASCII ذي 7 بتات ولا تستطيع التعامل مع بايتات ثنائية اعتباطية. يسد Base64 هذه الفجوة. تشمل حالات الاستخدام الشائعة في JavaScript: URIs للبيانات لتضمين الأصول، رؤوس HTTP Basic Auth، أجزاء رمز JWT، مرفقات البريد الإلكتروني MIME، وتخزين النقط الثنائية في JSON APIs.
ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=
deploy-bot:sk-prod-a7f2c91e4b3d8
btoa() — دالة الترميز الأصلية للمتصفح
btoa() (ثنائي إلى ASCII) متاحة في المتصفحات منذ IE10 وأصبحت عالمية في Node.js 16.0 كجزء من مبادرة توافق WinterCG. كما تعمل بشكل أصلي في Deno وBun وCloudflare Workers. لا حاجة لأي استيراد.
تأخذ الدالة وسيطة نصية واحدة وتُعيد شكلها المُرمَّز بـ Base64. النظير المتماثل atob() (ASCII إلى ثنائي) يفك ترميزه مجدداً. كلاهما متزامن ويعمل بذاكرة ثابتة نسبةً إلى حجم الإدخال.
مثال أدنى يعمل
// 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)
// 2KrZhSDYp9mE2KrYo9qp2K86INmF2K3ZhdWryp8g2KfZhNij2K3ZhdWryp8g4oCTINmF2LPYqtaqyp8g2KfZhNix2YrYp6...
console.log(decoded === orderNote) // trueBuffer.from(text, 'utf8').toString('base64'). إنه يعالج Unicode بشكل أصلي وأسرع للسلاسل الكبيرة.Buffer.from() في Node.js — دليل كامل مع أمثلة
في Node.js، Buffer هي واجهة برمجة التطبيقات المثالية لجميع عمليات البيانات الثنائية، بما في ذلك تحويلات الترميز. إنها تسبق TextEncoder بسنوات وتظل الخيار المفضل للكود من جانب الخادم. المزايا الرئيسية على btoa(): دعم UTF-8 الأصلي، ومعالجة البيانات الثنائية، واختصار ترميز '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ترميز الملفات غير المتزامن مع معالجة الأخطاء
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 — مرجع المعاملات
على عكس وحدة base64 في Python، لا تمتلك JavaScript دالة Base64 موحدة واحدة. تعتمد واجهة برمجة التطبيقات على البيئة المستهدفة. إليك المرجع الكامل لجميع النهج الأصلية:
| الدالة | نوع الإدخال | Unicode | آمن للروابط | متاح في |
|---|---|---|---|---|
| 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 | ✅ base64url في Node 18+ | 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:
Base64 الآمن للروابط — الترميز لـ JWTs والروابط وأسماء الملفات
يستخدم Base64 القياسي + و /، وهما محجوزان في الروابط — + يُفك ترميزه كمسافة في سلاسل الاستعلام، و / هو فاصل المسار. تتطلب JWTs ومعاملات الروابط وأسماء الملفات وقيم الكوكيز المتغير الآمن للروابط: + → -، / → _، إزالة = اللاحق.
المتصفح — استبدال الأحرف اليدوي
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) // editorترميز الملفات واستجابات API في JavaScript
في كود الإنتاج، يُطبَّق ترميز 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)
}
})جلب ملف ثنائي مُرمَّز بـ 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}`)عندما تحتاج فقط إلى فحص استجابة مُرمَّزة أثناء تصحيح أخطاء API دون إعداد سكريبت، الصق قيمة Base64 مباشرةً في مُرمِّز Base64 — يفك الترميز أيضاً مع إخراج فوري. مفيد لفحص استجابات GitHub API، وحمولات JWT، وتوقيعات webhook.
ترميز Base64 من سطر الأوامر في Node.js والشيل
لسكريبتات 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
واجهات برمجة التطبيقات المدمجة مناسبة لمعظم حالات الاستخدام. السبب الرئيسي للجوء إلى مكتبة هو الاتساق عبر البيئات: إذا شحنت حزمة تعمل في المتصفح وNode.js معاً، فإن استخدام Buffer يتطلب إما اكتشاف البيئة أو إعداد المجمّع، بينما تتطلب btoa() حل Unicode. تتعامل js-base64 (أكثر من 100 مليون تنزيل أسبوعي على 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 الأصلي عند توفره وتعود إلى تنفيذ JavaScript الخالص في المتصفح. إنها أسرع بـ 2–3× من نهج TextEncoder+btoa للسلاسل Unicode الكبيرة، وواجهة برمجة التطبيقات المتماثلة (toBase64 / fromBase64) تلغي العبء الذهني لتذكر اتجاه btoa و atob.
ترميز الملفات الثنائية الكبيرة مع تدفقات Node.js
عندما تحتاج إلى ترميز ملفات أكبر من ~50 ميغابايت، يصبح تحميل الملف بالكامل في الذاكرة مع 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 * 1024 * 256 = 786,432 بايت (768 كيلوبايت) — اضبط highWaterMark بناءً على ميزانية ذاكرتك. للملفات أقل من 50 ميغابايت، readFile() + Buffer.toString('base64') أبسط وسريع بما يكفي.الأخطاء الشائعة
راجعت كثيراً من قواعد كود JavaScript مع ترميز Base64، وتظهر هذه الأخطاء الأربعة باستمرار — غالباً غير مكتشفة حتى يصل حرف غير ASCII أو ملف ثنائي إلى مسار الترميز في الإنتاج.
الخطأ 1 — تمرير Unicode مباشرةً إلى btoa()
المشكلة: btoa() تقبل فقط الأحرف بنقاط الكود 0–255. الأحرف مثل ñ، أو الإيموجي، أو الحروف الصينية/اليابانية/الكورية تتسبب في DOMException فوري. الحل: رمِّز باستخدام TextEncoder أولاً، أو استخدم Buffer.from(text, 'utf8').toString('base64') في Node.js.
// ✅ 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('محمد الأحمد')
// 2YXYrdmF2K8g2KfZhNij2K3ZhdWr// ❌ DOMException: The string to be encoded contains // characters outside of the Latin1 range const username = 'محمد الأحمد' const encoded = btoa(username) // throws
الخطأ 2 — نسيان استعادة الحشو قبل atob()
المشكلة: يحذف Base64 الآمن للروابط حشو =. تمرير السلسلة المجردة مباشرةً إلى atob() ينتج إخراجاً غير صحيح أو يُطلق استثناء بحسب طول السلسلة. الحل: استعد + و/وأعد إضافة الحشو الصحيح قبل استدعاء atob().
// ✅ 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"}// ❌ atob() may return wrong data or throw // on URL-safe Base64 without padding const jwtSegment = 'eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2UifQ' const decoded = atob(jwtSegment) // Unreliable
الخطأ 3 — تسلسل الأجزاء المُرمَّزة بدلاً من المخازن الخام
المشكلة: كل استدعاء لـ btoa() أو .toString('base64') يضيف حشوه الخاص. تسلسل سلسلتي Base64 مُحشوَّتين ينتج إخراجاً غير صالح لأن الحشو ينتمي فقط في النهاية. الحل: تسلسل البيانات الخام قبل الترميز.
// ✅ Concatenate raw Buffers before encoding
const combined = Buffer.concat([
Buffer.from('webhook-secret'),
Buffer.from('-v2'),
]).toString('base64')
// d2ViaG9vay1zZWNyZXQtdjI= — single valid Base64 string// ❌ 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الخطأ 4 — استخدام response.text() لقراءة بيانات API الثنائية قبل الترميز
المشكلة: response.text() يفسر البايتات الخام بتنسيق UTF-8 ويستبدل تسلسلات البايت غير المعروفة بحرف الاستبدال U+FFFD. أي محتوى ثنائي — صور وملفات PDF وصوت — يتلف بصمت قبل وصوله إلى btoa(). الحل: استخدم response.arrayBuffer() للحصول على البايتات الخام.
// ✅ 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// ❌ 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طرق Base64 في JavaScript — مقارنة سريعة
| الطريقة | Unicode | بيانات ثنائية | آمن للروابط | البيئات | يتطلب تثبيت |
|---|---|---|---|---|---|
| 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 |
اختر btoa() فقط عندما يكون الإدخال مضموناً بأنه ASCII فقط — ملخصات hex أو معرّفات رقمية أو سلاسل Latin-1 محققة مسبقاً. للنصوص التي يوفرها المستخدم في المتصفح، استخدم TextEncoder + btoa(). لجميع كود Node.js من جانب الخادم، Buffer هو الخيار الافتراضي الصحيح. للمكتبات التي تحتاج إلى التشغيل في كلتا البيئتين دون تكوين المجمّع، js-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.