JavaScript/Node.js में Base64 एन्कोडिंग: एक सम्पूर्ण गाइड
आपके पास ऐसा डेटा है जिसे टेक्स्ट बनना है। एक फ़ाइल जो JSON फ़ील्ड के अंदर सफ़र करे, एक इमेज जो CSS फ़ाइल में बसे, एक सीक्रेट जो एनवायरनमेंट वैरिएबल में बैठे, एक टोकन जो क्वेरी स्ट्रिंग से गुज़रे। JavaScript और Node.js में जवाब लगभग हमेशा वही है: Base64। यह लेख वह पैकिंग मैन्युअल है, आपके हाथ के पहले बाइट से लेकर उस पल तक जब आपकी एन्कोडेड स्ट्रिंग मशीन से बाहर निकले।
इस साइट का होम पेज इस फ़ॉर्मेट की पूरी तफ़्सील बताता है - वर्णमाला, गणित, पैडिंग - इसलिए यहाँ एक वाक्य में: हर तीन बाइट्स चार प्रिंट होने वाले चर बन जाते हैं, इसलिए आपका आउटपुट इनपुट से लगभग 33 फ़ीसदी बड़ा होगा। यह अंक जेब में रखिए, क्योंकि इसीलिए इस लेख का हर सेक्शन मौजूद है, और आपका स्टोरेज बिल इसी अंक में गिनता है।
आराम की बात: आपको कुछ इंस्टॉल नहीं करना। हर मॉडर्न ब्राउज़र btoa() और नया Uint8Array.toBase64() लेकर आता है, और हर वह Node.js वर्ज़न जो मायने रखता है वह Buffer क्लास लेकर आता है, जिसमें 'base64' मोड है, और वर्ज़न 15.7.0 से पहली कतार का 'base64url' मोड। हुनर यह जानने में है कि आप किस आकार का इनपुट पकड़े हैं, मंज़िल कौन सी वर्णमाला माँगती है, और पुराने फ़ॉर्मेट आज भी कौन से लाइन-रैपिंग नियम लागू करते हैं।
एन्कोड से पहले अपना इनपुट पहचानें
हर एन्कोडिंग सवाल वही पहला सवाल लेकर शुरू होता है: आप ठीक-ठीक क्या पकड़े हैं? JavaScript स्ट्रिंग UTF-16 टेक्स्ट है, Buffer बाइट्स का अर्रे है, और सही कॉल इस बात पर निर्भर करता है कि आप पकड़े कौन सा है:
| आप पकड़े हैं | यह कॉल कीजिए | नोट्स |
|---|---|---|
| सिर्फ़ ASCII वाली स्ट्रिंग (256 से नीचे के चर) | btoa(string) |
ब्राउज़र और Node.js 16+ में सबसे तेज़ रास्ता, परंतु यह पहले ऐसे चर पर रुक जाता है जो एक बाइट में नहीं समाता |
| कोई भी Unicode स्ट्रिंग | TextEncoder से बाइट्स, फिर एक base64 कॉल |
UTF-8 पुल; एक्सेंट वाले अक्षरों और इमोजी के लिए एकमात्र सुरक्षित रास्ता |
| Buffer या Uint8Array | buffer.toString('base64') या bytes.toBase64() |
Node.js वर्कहॉर्स, और मॉडर्न ब्राउज़र और Node.js 25+ में ES2026 तरीका |
तीन उदाहरण, टेबल की हर पंक्ति का एक-एक:
// सिर्फ़ ASCII टेक्स्ट: पुराना शॉर्टकट (ब्राउज़र और Node.js 16+)
console.log(btoa('hello world')); // "aGVsbG8gd29ybGQ="
// Node.js में कोई भी टेक्स्ट: Buffer डिफ़ॉल्ट में UTF-8 पढ़ता है
const { Buffer } = require('node:buffer');
console.log(Buffer.from('héllo ⛳', 'utf8').toString('base64')); // "aMOpbGxvIOKbsw=="
// बाइट्स जो आपके पास पहले से हैं
console.log(Buffer.from([1, 2, 3, 4]).toString('base64')); // "AQIDBA=="
console.log(new Uint8Array([1, 2, 3, 4]).toBase64()); // "AQIDBA==" (ES2026 रनटाइम्स)
दूसरे उदाहरण की तरफ़ ध्यान दीजिए: वही टेक्स्ट किस कैरेक्टर सेट में एन्कोड करें, इस पर निर्भर करके अलग Base64 स्ट्रिंग देता है। यह त्रुटि नहीं है - यह पूरा खेल है। Base64 तह बाइट्स एन्कोड करती है, और स्ट्रिंग तब ही बाइट्स बनती है जब आपने कैरेक्टर सेट चुन लिया हो, इसलिए "इस टेक्स्ट को एन्कोड कीजिए" का असल मतलब "इस टेक्स्ट के UTF-8 बाइट्स को एन्कोड कीजिए" होता है (अगर आपने कहा हो तो Latin-1 बाइट्स)।
Unicode दीवार और उसके ऊपर के पुल
btoa() इस कमरे की सबसे पुरानी API है, और उसका वादा 1990s का है: इनपुट स्ट्रिंग का हर चर एकल बाइट में समा जाए, कोड पॉइंट 0 से 255 के बीच। उससे ऊपर का कुछ भी - एक इमोजी, एक्सेंट वाला सिरिलिक अक्षर, चीनी चर - फेंक देता है:
try {
btoa('héllo ⛳');
} catch (error) {
console.log(error.name); // "InvalidCharacterError"
console.log(error.message); // Node में "Invalid character"; ब्राउज़र में Latin1-रेঞ্জ वाला अल्फ़ाज़
}
इलाज है: चर सोचना छोड़ दीजिए और बाइट्स सोचना शुरू कीजिए। TextEncoder (हर ब्राउज़र और Node.js में ग्लोबल) स्ट्रिंग को उसके UTF-8 बाइट क्रम में बदल देता है; आप उन बाइट्स को Latin-1 स्ट्रिंग में उठाते हैं, और btoa() को बिल्कुल वही मिलता है जिसका उसने वादा किया था:
function encodeUnicode (text) {
const bytes = new TextEncoder().encode(text);
let binary = '';
for (const byte of bytes) {
binary += String.fromCharCode(byte);
}
return btoa(binary);
}
console.log(encodeUnicode('héllo ⛳')); // "aMOpbGxvIOKbsw=="
console.log(encodeUnicode('héllo ⛳') === Buffer.from('héllo ⛳', 'utf8').toString('base64')); // true, वही बाइट्स
आप कोडबेस में पुराना आइडियम भी मिलेगा, और नीचे से वह भी इसी तरह काम करता है: btoa(unescape(encodeURIComponent(text)))। encodeURIComponent कॉल से पर्सेंट-एन्कोडेड UTF-8 बाइट्स बनते हैं, और unescape उन पर्सेंट एस्केप्स को वापस राव चर में बदल देता है। escape और unescape दोनों डिप्रिकेटेड लीगेसी फ़ंक्शन हैं, इसलिए नए कोड को TextEncoder पुल पसंद करना चाहिए, परंतु जब आपको पुराना रूप विरासत में मिले, अब आपको बिल्कुल पता है कि वह क्या कर रहा है, कंधे उचलने के बजाय।
Node.js में यह दीवार ज़्यादातर कोई घटना ही नहीं है, क्योंकि Buffer.from(text) UTF-8 मानता है और वही कॉल में बाइट कन्वर्ज़न कर देता है। पुल ब्राउज़र में सबसे ज़्यादा काम आता है, जहाँ btoa() लीगेसी विकल्प है और UTF-8 का कदम आपको खुद एक्सप्लिसिट रूप से उठाना होता है।
बाइट अंदर, अक्षर बाहर: बफ़र, पैडिंग और किस्में
एक बार बाइट्स हाथ में आ गए, तो Node.js की एन्कोडिंग तह एक मेथड है: toString('base64')। यह ग्रुप का गणित, पैडिंग, सब कुछ संभालता है, और यह हमेशा RFC 4648 अर्थ में कैनोनिकल आउटपुट देता है, यानी आख़िरी ग्रुप के बेकार पैड बिट्स शून्य होते हैं:
const { Buffer } = require('node:buffer');
const fox = Buffer.from('The quick brown fox jumps over the lazy dog');
console.log(fox.length); // 43 बाइट्स
console.log(fox.toString('base64')); // "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="
console.log(fox.toString('base64').length); // 60 चर, 33 फ़ीसदी टैक्स काम पर
अंत की पैडिंग असली काम करती है, सजावट नहीं। एक अंतिम ग्रुप जिसमें एक बचा बाइट हो, वह दो Base64 चर और दो = बनता है, और जिसमें दो बचे बाइट्स हों वह तीन चर और एक =। आपका आउटपुट वह पैडिंग सह सके या नहीं, इसका फैसला मंज़िल करती है, और यही अंतर है उसी दो Base64 किस्मों के बीच जो आप रोज़ इस्तेमाल करेंगे:
const one = new Uint8Array([72]);
console.log(one.toBase64()); // "SA==" (ES2026, पैडिंग के साथ)
console.log(one.toBase64({ omitPadding: true })); // "SA"
console.log(Buffer.from([72]).toString('base64url')); // "SA", Node base64url मोड में पैडिंग छोड़ देता है
चीज़ें साइज़ करने के लिए अनुपात याद रखिए: तीन बाइट्स अंदर, चार चर बाहर, इसलिए 1 MB डेटा लगभग 1.33 MB टेक्स्ट बनता है, और अगर आप ईमेल या PEM के लिए टेक्स्ट को लाइनों में रैप करते हैं, तो लाइन ब्रेक्स ऊपर से कुछ फ़ीसदी और जोड़ देते हैं।
बाइट्स को तार पर पार कराना
JavaScript की सबसे आम तार-समस्या यह है कि JSON में बाइट्स नहीं होते। उसमें स्ट्रिंग्स हैं, और वह स्ट्रिंग जो किसी भी JSON पार्सर, किसी भी HTTP प्रॉक्सी और किसी भी लॉगिंग सिस्टम से सुरक्षित गुज़र सके, वह Base64 वाली है। पैटर्न कनेक्शन के दोनों सिरों पर वही है: बाउंडरी पर एन्कोड कीजिए, बाउंडरी पर डिकोड कीजिए, बीच में बाइट्स पकड़िए:
const fs = require('node:fs');
const photo = fs.readFileSync('./photo.jpg', 'base64');
const payload = JSON.stringify({
name: 'photo.jpg',
contentType: 'image/jpeg',
data: photo
});
console.log(payload.startsWith('{"name":"photo.jpg"')); // true, फ़ाइल अब साधारण JSON के अंदर सफ़र करती है
यह पैटर्न कब लड़ना है, यह भी जानिए। अगर आपका ट्रांसपोर्ट पहले से बाइनरी समझता है, तो उसे ही लीजिए: multipart/form-data अपलोड राव फ़ाइल बिना साइज़ टैक्स के भेजता है, WebSocket फ्रेम राव बाइट्स ले जाता है, और Postgres bytea कॉलम उन्हें नेटिव रूप में सहेजता है। जहाँ राव बाइट्स की इज़ाज़त थी वहाँ Base64 शुद्ध अतिरिक्त बोझ है, 33 फ़ीसदी टैक्स जिसका बदले में कुछ नहीं मिलता। Base64 तब कमाता है जब चैनल सिर्फ़ टेक्स्ट वाला हो: JSON API, ईमेल बॉडीज़, एनवायरनमेंट वैरिएबल्स, URL क्वेरी स्ट्रिंग्स, और ब्रिजों की लंबी कतार (मोबाइल SDK, डेस्कटॉप ऐप्स, चैट सिस्टम) जो सिर्फ़ टेक्स्ट ही गुज़रने देते हैं।
Data URLs: टेक्स्ट में रहने वाली तस्वीरें
data URL, वह data:image/png;base64,... स्ट्रिंग, Base64 का MIME लेबल पहने रूप है, और इसीलिए आप पूरी इमेज एक ही HTML एट्रिब्यूट के अंदर रख सकते हैं। 1998 का वह RFC जिसने यह स्कीम तय की, उसमें लिखा है कि यह "सिर्फ़ छोटे मानों के काम आता है", क्योंकि शुरुआती HTML में एट्रिब्यूट मानों पर 1024-चर की सीमा थी। मॉडर्न ब्राउज़र उस सीमा पर हँसते हैं और मेगाबाइट-आकार के data URLs की ख़ुशी से रेंडरिंग करते हैं, जो सुपरपावर भी है और फँदा भी।
ब्राउज़र में कैनवास API पूरा काम आपके लिए कर देता है, पिक्सेल अंदर, data URL बाहर:
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
const context = canvas.getContext('2d');
context.fillStyle = '#ff0000';
context.fillRect(0, 0, 1, 1);
const dataUrl = canvas.toDataURL('image/png'); // "data:image/png;base64,iVBOR..."
console.log(dataUrl.slice(0, 24)); // "data:image/png;base64,iV"
और किसी भी रनटाइम में, Node.js समेत, बनाना बस मेटाडेटा को सही जगह रखकर स्ट्रिंग कनेटनेशन है: data: प्रिफ़िक्स, मीडिया टाइप, वैकल्पिक ;base64 मार्कर, एक कॉमा, और पेलोड। बिना ;base64 मार्कर के पेलोड का पर्सेंट-एन्कोडेड टेक्स्ट होने की उम्मीद होती है, और यही वजह है कि मार्कर मौजूद है:
const { Buffer } = require('node:buffer');
const png = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB', 'base64');
const dataUrl = 'data:image/png;base64,' + png.toString('base64');
console.log(dataUrl.startsWith('data:image/png;base64,')); // true
ईमानदार लेन-देन: data URL दस्तावेज़ का हिस्सा है, इसलिए वह अपने आप कोर्स संसाधन के तौर पर कैशेबल नहीं है, वह जिस HTML या CSS में बैठे है उसकी साइज़ में गिनती देता है, और DOM को उसे पार्स करके पकड़ा रहना पड़ता है। 20 किलोबाइट आइकॉन के लिए यह सौदा है। 4 मेगाबाइट हीरो इमेज के लिए, फ़ाइल को HTTP से भेजिए जहाँ कैशिंग और कॉम्प्रेशन दोनों काम करते हैं, और data URL छोटी चीज़ों के लिए ही रखिए।
स्ट्रिंग बनकर सफ़र करने वाली फ़ाइलें
फ़ाइल से Base64 दो-कदम की नृत्य है, जो दोनों रनटाइम्स एक ही कॉल में निपटा देते हैं। Node.js में फ़ाइल सिस्टम रीड एन्कोडिंग के तौर पर 'base64' मानता है, और लिखने की तरफ भी:
const fs = require('node:fs');
const { Buffer } = require('node:buffer');
const base64 = fs.readFileSync('./report.pdf', 'base64');
console.log(base64.length); // फ़ाइल, लगभग 33 फ़ीसदी भारी
fs.writeFileSync('./report.pdf.b64', base64, 'utf8');
const copy = Buffer.from(base64, 'base64');
fs.writeFileSync('./report.copy.pdf', copy);
ब्राउज़र में FileReader वही काम करता है, एक मोड़ के साथ: उसका डेटा-रीडिंग मोड आपको data URL देता है, इसलिए प्रिफ़िक्स काटिए - जो बचे वही राव Base64 पेलोड है:
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', () => {
const reader = new FileReader();
reader.onload = () => {
const dataUrl = reader.result; // "data:application/pdf;base64,..."
const payload = {
name: fileInput.files[0].name,
data: dataUrl.slice(dataUrl.indexOf(',') + 1)
};
console.log(payload.data.length); // फ़ाइल, JSON रिक्वेस्ट के लिए तैयार
};
reader.readAsDataURL(fileInput.files[0]);
});
अगर ब्राउज़र में आपको data URL प्रिफ़िक्स के बिना राव Base64 चाहिए, तो file.arrayBuffer() के बाद Uint8Array.toBase64() (जो रनटाइम्स हैं वहाँ) प्रिफ़िक्स ही नहीं छूता और अपलोड पाइपलाइन्स के लिए साफ़ रास्ता है।
base64url: वह वर्णमाला जो URL में बच जाती है
क्लासिक Base64 दो ऐसे चर लेकर चलता है जिनसे URL की अलर्जी है। + क्वेरी स्ट्रिंग फ़ॉर्म-डिकोड होते ही स्पेस बन जाता है, / पथ सेपरेटर है, और = पैडिंग एसाइनमेंट जैसी दिखती है। RFC 4648 सेक्शन 5 की URL- और फ़ाइलनेम-सुरक्षित किस्म, base64url, इन दोनों ख़ासियों को - और _ से बदलती है, और जब लेंथ संदर्भ से पता हो तो पैडिंग ही छोड़ देती है। यह JWTs, OAuth टोकन और डीप लिंक्स की वर्णमाला है, और आपके ज़ेहन के टूलकिट में इसे अपना अलग ठिकाना मिलना चाहिए।
Node का Buffer इस बोली से वर्ज़न 15.7.0 से बात करता आ रहा है, और एन्कोडिंग की तरफ यह एक अर्ग्यूमेंट है:
const { Buffer } = require('node:buffer');
const classic = 'k+XS/B4=';
console.log(Buffer.from(classic, 'base64').toString('base64url')); // "k-XS_B4"
दो बातें नोट करें। + बनकर - हो गया, / बनकर _ हो गया, और पैडिंग गायब हो गई, क्योंकि base64url मोड डिज़ाइन से ही उसे छोड़ता है। और IETF एक्सप्लिसिट कहता है कि यह एक अलग एन्कोडिंग है, वही एन्कोडिंग कपड़ा बदलकर नहीं, इसलिए जब कोई स्पेसिफिकेशन "base64url" कहता है, तो base64url बनाइए, फ़ाइंड-एंड-रिप्लेस वाला क्लासिक Base64 नहीं। ES2026 तरीका वही विकल्प एक्सप्लिसिट ऑप्शन बना देता है, और उसका omitPadding फ़्लैग तब पैडिंग वापस देता है जब संदर्भ माँगता है:
console.log(new Uint8Array([0xab, 0xff]).toBase64({ alphabet: 'base64url', omitPadding: true })); // "q_8"
console.log(new Uint8Array([0xab, 0xff]).toBase64({ alphabet: 'base64url' })); // "q_8=", दो बाइट्स को एक पैड चर चाहिए
जो रनटाइम्स किसी में भी नहीं हैं, वहाँ कन्वर्ज़न दो-चर स्वैप और पैडिंग ट्रिम है, और यह JavaScript दुनिया के सबसे ज़्यादा कॉपी-पेस्ट किए जाने वाले स्निपेट्स में से एक है:
const toUrlSafe = (value) => value.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
console.log(toUrlSafe('k+XS/B4=')); // "k-XS_B4"
URL, क्वेरी स्ट्रिंग, फ़ाइलनेम, या टोकन स्टैंडर्ड में बसने वाली किसी भी चीज़ के लिए base64url का इस्तेमाल कीजिए। MIME बॉडीज़, data URLs और उस चीज़ के लिए क्लासिक Base64 जिसका पर्सेंट-डिकोडर से कभी सामना नहीं होगा। इन दोनों में भ्रम होना इस पूरे फ़ॉर्मेट की सबसे आम इंटरॉप बग है।
क्रेडेंशियल्स की सील: Basic Auth, JWTs और PKCE
वेब की तीन ऑथेंटिकेशन कोनों ने Base64 पर निर्माण किया है, और तीनों को हाथ से एक बार बनाना सस्ता है, जो अच्छी बात है, क्योंकि लाइब्रेरी के नीचे क्या चलता है यह जानना ही वही चीज़ है जो लाइब्रेरी आपको चौंकाए तब शांत रखती है।
पहली, HTTP Basic ऑथेंटिकेशन (RFC 7617): क्लाइंट स्कीम शब्द Basic और user-id:password का Base64 भेजता है। एक लाइन, और साथ में एक गंभीर चेतावनी:
const { Buffer } = require('node:buffer');
console.log('Basic ' + Buffer.from('octo:cat').toString('base64')); // "Basic b2N0bzpjYXQ="
यहाँ Base64 छिपापन है, सुरक्षा नहीं। जो भी हेडर पढ़ सकता है वह पासवर्ड पढ़ सकता है, इसलिए यह स्कीम सिर्फ़ HTTPS पर स्वीकार्य है, और तब भी यह लीगेसी पैटर्न है: टोकन को प्राथमिकता दीजिए। दूसरा, JWT: पहले दो डॉट-सेपरेटेड हिस्से सादे JSON के base64url हैं, और तीसरा सिग्नेचर है। हाथ से HMAC-SHA256 टोकन बनाना बिल्ट-इन crypto मॉड्यूल की कुछ ही लाइनें हैं:
const crypto = require('node:crypto');
const header = Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).toString('base64url');
const payload = Buffer.from(JSON.stringify({ sub: 'octocat', exp: 1893456000 })).toString('base64url');
const signature = crypto.createHmac('sha256', 'topsecret').update(header + '.' + payload).digest('base64url');
const token = header + '.' + payload + '.' + signature;
console.log(token.split('.').length); // 3 हिस्से, हर जगह बिना पैडिंग base64url
वही विवरण टोकन को बनाते-तोड़ते हैं, उन्हें नोट कीजिए: हर जगह पैडिंग नहीं (RFC 7515 उसे छोड़ता है), सिग्नेचर header + '.' + payload वाली स्ट्रिंग पर, बिल्कुल उसी रूप में, गिना जाता है - पार्स किए गए ऑब्जेक्ट्स पर नहीं, और यह सब जितना ही सीक्रेट है जितना की। प्रोडक्शन में आप लाइब्रेरी इस्तेमाल करेंगे, jose (शून्य डिपेंडेंसी, ब्राउज़र और Node.js) या jsonwebtoken (Node.js), परंतु उनके नीचे से वही यही कॉल चल रही हैं। तीसरा, PKCE (RFC 7636), वह एक्सटेंशन जो SPA और मोबाइल ऐप्स जैसे पब्लिक क्लाइंट्स को सुरक्षित लॉगिन कराने देता है: क्लाइंट हाई-एंट्रोपी code_verifier जेनरेट करता है, BASE64URL(SHA256(verifier)) को चैलेंज के तौर पर प्रकाशित करता है, और टोकन एक्सचेंज पर वेरिफ़ायर के कब्ज़े का प्रमाण देता है। रैंडमनेस काम आती है, इसलिए वेरिफ़ायर क्रिप्टो मॉड्यूल से आता है, कभी Math.random() से नहीं:
const verifier = crypto.randomBytes(32).toString('base64url');
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
console.log(verifier.length, challenge.length); // 43 43, दोनों अनुमत 43-128 रेंज के अंदर
पुरानी चिट्ठियों को रैप चाहिए: MIME और PEM आर्मर
दुनिया के दो सबसे पुराने Base64 फ़ॉर्मेट आज भी लाइन लेंथ लागू करते हैं, और दोनों करीब 30 साल पुराने हैं। MIME, RFC 2045 का ईमेल स्टैंडर्ड, अपना Base64 76 चर प्रति लाइन पर रैप करता है और लाइनों के अंत में CRLF ज़रूरी है, 8-bit-clean SMTP के दिनों का एक अवशेष, जब बहुत लंबी लाइनें असली मेल सर्वर्स को तोड़ देती थीं। RFC 7468, जिसने सर्टिफिकेट्स और कुंजियों के लिए PEM के नियम लिखे, और भी सख़्त है: जेनरेटर को हर लाइन बिल्कुल 64 चर पर रैप करनी होती है, आख़िरी लाइन छोटी, और -----BEGIN और -----END आर्मर लाइनों से घिरा, जो कंटेंट का नाम रखती हैं।
रैपिंग खुद एक लाइनर है, और आर्मर एक टेम्पलेट:
const wrap = (base64, width) => base64.match(new RegExp('.{1,' + width + '}', 'g')).join('\r\n');
const certBase64 = Buffer.from('x'.repeat(150), 'utf8').toString('base64'); // 200 चर
console.log(wrap(certBase64, 76).split('\r\n').map((line) => line.length).join(', ')); // "76, 76, 48"
console.log(wrap(certBase64, 64).split('\r\n').map((line) => line.length).join(', ')); // "64, 64, 64, 8"
const armor = (label, body) => '-----BEGIN ' + label + '-----\r\n' + wrap(body, 64) + '\r\n-----END ' + label + '-----\r\n';
console.log(armor('CERTIFICATE', 'QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo='));
// -----BEGIN CERTIFICATE-----
// QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=
// -----END CERTIFICATE-----
दो प्रैक्टिकल नोट्स। जब आप MIME या PEM बनाएँ, तो रैप कीजिए, क्योंकि सख़्त उपभोक्ता (मेल गेटवेज़, OpenSSL-एरा टूल्स, Java की स्टोर्स) 4000-चर की एक-लाइन Base64 ब्लॉब को मंज़ूर नहीं करेंगे। जब आप उसे पढ़ें, तो ज़्यादातर ज़रूरत नहीं, क्योंकि Node का डिकोडर व्हाइटस्पेस छोड़ देता है, इसलिए Buffer.from लाइन ब्रेक्स आपके लिए संभाल लेता है - परंतु आर्मर लाइनें खुद Base64 नहीं हैं, इसलिए डिकोड करने से पहले -----BEGIN/-----END लाइनें हटा दीजिए (या सिर्फ़ बॉडी मैच कीजिए): Buffer.from(pem.replace(/-----[A-Z ]+-----/g, ''), 'base64')। यह असममितता तोहफ़ा है, परंतु इसका मतलब यह नहीं कि आप आर्मर-स्ट्रिपिंग कदम छोड़ सकते हैं, जब Base64 कहीं ऐसे जा रहा हो जो कुछ भी छुड़ाए नहीं, जैसे DER पार्सर।
एन्कोडेड डेटा कहाँ रहता है: Env, कॉन्फ़िग और डेटाबेस
Base64 एक स्टोरेज फ़ॉर्मेट भी है, जो इतनी सुविधाजनक है कि उसे सुरक्षा समझ लेना खतरनाक आसान हो जाता है। एनवायरनमेंट वैरिएबल्स क्लासिक घर हैं: कई सीक्रेट मैनेजर्स और CI सिस्टम आपको Base64-एन्कोडेड वैल्यूज़ देते हैं, और डिकोड एक लाइनर है:
const { Buffer } = require('node:buffer');
const stored = process.env.API_KEY_B64; // "c3VwZXItc2VjcmV0"
console.log(Buffer.from(stored, 'base64').toString('utf8')); // "super-secret"
जुबानी महत्वपूर्ण वाक्य बोलें: एन्कोडिंग एन्क्रिप्शन नहीं है। एनवायरनमेंट वैरिएबल, .env फ़ाइल या Kubernetes सीक्रेट (k8s अपने सीक्रेट्स API और etcd में Base64 के रूप में सहेजता है, और दस्तावेज़ बार-बार यह दोहराते हैं) में Base64 "सीक्रेट" वह हर कोई पढ़ सकता है जो प्रोसेस एनवायरनमेंट, फ़ाइल, या क्लस्टर पढ़ सकता है। वहाँ Base64 उसीलिए इस्तेमाल कीजिए क्योंकि ट्रांसपोर्ट (शेल, YAML, JSON) सिर्फ़ टेक्स्ट वाला है, कभी इस मान से नहीं कि वह कुछ छुपाता है।
डेटाबेस में, Base64 बाइनरी को JSON डॉक्यूमेंट स्टोर्स के अंदर ले जाने का स्टैंडर्ड ब्रिज है, क्योंकि jsonb कॉलम या MongoDB डॉक्यूमेंट का अपना बाइट टाइप नहीं होता:
const document = {
name: 'logo',
mime: 'image/png',
data: Buffer.from([0x89, 0x50, 0x4e, 0x47]).toString('base64')
};
console.log(JSON.stringify(document)); // {"name":"logo","mime":"image/png","data":"iVBORw=="}
पेलोड के बगल में मीडिया टाइप सहेजिए, जैसे उदाहरण करता है, और एक साल बाद आप खुद को धन्यवाद देंगे, जब कोई पूछे कि ये बाइट्स क्या हैं। अगर आपके डेटाबेस का नेटिव बाइनरी टाइप है (Postgres bytea रेफ़रेंस उदाहरण है), तो उसे ही पसंद कीजिए: बाइट्स की कोई अतिरिक्त कीमत नहीं, और 33 फ़ीसदी टैक्स हमेशा के लिए टल जाता है।
ग्रुप्स न तोड़कर स्ट्रीम्स एन्कोड करना
Base64 तीन-बाइट ग्रुप्स में काम करता है, इसलिए कोई एन्कोडर जो कोई भी चंक्स ले, उसे अपनी बचावत संभालनी पड़ती है: एक-दो बाइट्स जो अभी ग्रुप नहीं बना पाए, अगले चंक का इंतज़ार करते हैं। हर चंक पर गणित कीजिए और सिर्फ़ पूरे ग्रुप्स निकालिए, तो आउटपुट पूरी स्ट्रीम को एक साथ एन्कोड करने से बाइट-दर-बाइट वही रहेगा:
const { Transform } = require('node:stream');
const { Buffer } = require('node:buffer');
function base64Encoder () {
let pending = Buffer.alloc(0);
return new Transform({
transform (chunk, _encoding, done) {
pending = Buffer.concat([pending, chunk]);
const whole = Math.floor(pending.length / 3) * 3;
this.push(pending.subarray(0, whole).toString('base64'));
pending = pending.subarray(whole);
done();
},
flush (done) {
if (pending.length > 0) {
this.push(pending.toString('base64'));
}
done();
}
});
}
let output = '';
const encoder = base64Encoder();
encoder.on('data', (part) => { output += part; });
encoder.on('end', () => {
console.log(output); // "aGVsbG8gd29ybGQsIHRoaXMgaXMgYSBzdHJlYW0h"; एक बड़ी toString('base64') से एक जैसा
});
encoder.end(Buffer.from('hello world, this is a stream!'));
flush कॉलबैक वही विवरण है जिसके बारे में सब भूल जाते हैं: आख़िरी एक-दो बाइट्स, जिन्हें किसी सामान्य चंक में साथी कभी नहीं मिला, उन्हें अपनी पैडिंग मिलकर अंत में बाहर निकाल दी जाती हैं। वही कैरी लॉजिक है जो आप डिकोडिंग की तरफ प्रतिकृति करेंगे, सिवाय इसके कि वहाँ ES2026 API उसे मुफ़्त देता है: setFromBase64() के साथ "stop-before-partial" बिल्कुल ग्रुप बाउंडरी पर रुकता है और बताता है कि उसने कितने चर खपते।
बड़ी फ़ाइलें और मेमोरी का बिल
Base64 जगह में बड़ा उदार है, इसलिए बड़ी फ़ाइलों को रणनीति चाहिए। 1 GB फ़ाइल लगभग 1.33 GB Base64 टेक्स्ट बनती है, और JavaScript स्ट्रिंग UTF-16 सहेजती है, हर चर के लिए दो हेप बाइट्स, इसलिए वह टेक्स्ट अकेले आपका Buffer आने से पहले लगभग 2.7 GB मेमोरी माँगता है। सीमा Node में एक्सप्लिसिट है: buffer.constants.MAX_STRING_LENGTH 536870888 चर है, टेक्स्ट में 512 MiB से बस नीचे, जो लगभग 400 MB बाइट्स में डिकोड होता है। उसके बाद एक स्ट्रिंग विकल्प ही नहीं बचा, और स्ट्रीमिंग ही शहर का एकमात्र खेल है:
const fs = require('node:fs');
const { Buffer } = require('node:buffer');
let carried = Buffer.alloc(0);
const source = fs.createReadStream('./video.mp4', { highWaterMark: 64 * 1024 });
source.on('data', (chunk) => {
const joined = Buffer.concat([carried, chunk]);
const whole = Math.floor(joined.length / 3) * 3;
process.stdout.write(joined.subarray(0, whole).toString('base64'));
carried = joined.subarray(whole);
});
source.on('end', () => {
if (carried.length > 0) {
process.stdout.write(carried.toString('base64'));
}
process.stdout.write('\n');
});
पैटर्न पिछले सेक्शन का स्ट्रीम एन्कोडर है, सपाट किया हुआ: 64 KiB चंक्स में पढ़िए, 1-2 बाइट की बचावत संभालिए, पूरे ग्रुप्स निकालिए, पूंछ फल्श कीजिए। मेमोरी का फ़ुटप्रिंट लगभग एक चंक प्लस एक बचावत पर रहता है, फ़ाइल का वज़न जो भी हो। और अगर लेने वाला सिरा बाइनरी स्वीकार कर सके, तो खुद से पूछिए कि आप टैक्स का भुगतान ही क्यों कर रहे हैं।
टर्मिनल के लिए वन-लाइनर
Node एक कमांड-लाइन Base64 एन्कोडर के तौर पर भी काम आता है, जो तब काम आता है जब आप कॉन्फ़िग मान पैक कर रहे हों, किसी API को डिबग कर रहे हों, या किसी चैट मैसेज से छोटी फ़ाइल को एक मशीन से दूसरी में ले जा रहे हों:
# फ़ाइल को stdout पर क्लासिक Base64 में एन्कोड करें
node -e 'const fs=require("node:fs");process.stdout.write(fs.readFileSync(process.argv[1],"base64"))' notes.txt
# URL-सुरक्षित किस्म, पैडिंग छोड़ी हुई
node -e 'const fs=require("node:fs");process.stdout.write(fs.readFileSync(process.argv[1],"base64url"))' notes.txt
# stdin से पढ़ें, पाइप्स के लिए ही तो बने हैं
echo -n "hello world" | node -e 'let d="";process.stdin.on("data",c=>d+=c).on("end",()=>process.stdout.write(Buffer.from(d,"utf8").toString("base64")))'
तीनों में से कोई भी अपने आप अंत में नई लाइन नहीं जोड़ता, जिससे आउटपुट कॉपी-पेस्ट और शेल स्क्रिप्ट्स में $(...) रिप्लेसमेंट के लिए साफ़ रहता है। अगर आप रैप लाइनों के साथ सजी हुई फ़ाइल चाहते हैं, तो परिणाम को अपने पसंदीदा एडिटर में पाइप कर दीजिए, या वन-लाइनर के अंत में \n जोड़ दीजिए।
वह फँदे जो डेवलपर्स को घंटों खर्च कराते हैं
इनमें से हर एक ने किसी असली कोडबेस में कोई असली दोपहर खर्च कराई है:
- Unicode दीवार:
btoa('héllo ⛳')InvalidCharacterErrorफेंकता है, क्योंकि गोल्फ़ झंडा एक बाइट में नहीं समाता। इलाज UTF-8 पुल है: पहलेTextEncoderसे बाइट्स, फिर एन्कोड। Node.js मेंBuffer.from(text)से समस्या ही नहीं बनती, वह UTF-8 मानता है। - लीगेसी आइडियम: पुराने कोड में जगह-जगह
btoa(unescape(encodeURIComponent(x)))काम करता है, परंतुescapeऔरunescapeडिप्रिकेटेड लीगेसी फ़ंक्शन हैं। जब आप उस कोड को रिफ़ैक्टर करें, तो उसेTextEncoderपुल से बदल दीजिए और व्यवहार बिल्कुल वही रहेगा। - गुम एन्कोडिंग अर्ग्यूमेंट, उल्टी तरफ से: डिकोड-तरफ का फँदा
Buffer.from(str)है 'base64' मोड के बिना; एन्कोड-तरफ का जुड़वा यह मानना है किBuffer.from(someString)Base64 के साथ कुछ ख़ास करता है। नहीं करता। बिना एक्सप्लिसिट एन्कोडिंग के वह स्ट्रिंग के UTF-8 बाइट्स से Buffer बनाता है, और आपका "एन्कोडेड" आउटपुट स्ट्रिंग के अक्षरों के UTF-8 बाइट्स का Base64 बन जाता है, जो लगभग कभी वही नहीं होता जो चाहिए था। दोनों दिशाओं में एक्सप्लिसिट रहिए। - पैडिंग मेल-खा न रहना: JWTs और ज़्यादातर टोकन स्टैंडर्ड बिना पैडिंग वाले base64url चाहते हैं, MIME पैडिंग वाले क्लासिक Base64, और दोनों आसानी से आपस में मिल जाते हैं। JWT हिस्से के अंदर पैड वाला
=सख़्त वेरिफायर्स को तोड़ देता है; जहाँ लेंथ अज्ञात हो वहाँ पैडिंग न होने से आलसी डिकोडर टूटते हैं। स्टैंडर्ड के साथ मिलाइए, अपनी आदत के साथ नहीं। - नॉन-कैनोनिकल पूंछ: RFC 4648 आख़िरी ग्रुप के बेकार पैड बिट्स को शून्य माँगता है। बिल्ट-इन एन्कोडर सारे कैनोनिकल आउटपुट देते हैं, परंतु हाथ से लिखा एन्कोडर जो बिट्स हाथ से शिफ़्ट करे, उन बिट्स में कचरा छोड़ सकता है, और सख़्त डिकोडर आपका पेलोड बिना किसी ज़ाहिर के कारण के मंज़ूर नहीं करेगा। अगर आप अपना एन्कोडर लिखते हैं, तो अपना डेटा नहीं, RFC 4648 के टेस्ट वैक्टर के ख़िलाफ़ टेस्ट कीजिए।
- भुली हुई रैप: MIME 76-चर लाइनें माँगता है और PEM 64, और सख़्त उपभोक्ता (मेल गेटवेज़, Java की टूलिंग) एक-लाइन ब्लॉब को मंज़ूर नहीं करते। उल्टी तरफ़ की बात कम आम परंतु असली है: कुछ पार्सर लाइन-ओरिएंटेड होते हैं, और PEM फ़ाइल के अंत में CRLF न होने से Base64 की किसी भी बग से ज़्यादा बिल्ड टूटे हैं।
- सुरक्षा का भ्रम: एनवायरनमेंट वैरिएबल,
.envफ़ाइल या Kubernetes सीक्रेट में Base64 एन्क्रिप्शन नहीं है। वह एक लाइन कोड में, किसी भी भाषा में, उस हर किसी के लिए डिकोड हो जाता है जो फ़ाइल या क्लस्टर पढ़ सकता है। उसे ट्रांसपोर्ट का कपड़ा समझिए, और असली कंट्रोल्स (परमिशन, TLS, की रोटेशन) को ही सुरक्षा करते रहने दीजिए। - JSON सूजन: JSON के अंदर Base64 33 फ़ीसदी प्लस एस्केपिंग लगता है, और 5 MB अपलोड 6.7 MB स्ट्रिंग बन जाता है जिसे आपके JSON पार्सर को मेमोरी में कॉपी करना पड़ता है। HTTP पर कुछ भी फ़ाइल-आकार के लिए,
multipart/form-dataया राव बाइनरी बॉडी बेहतर ट्रांसपोर्ट है, और Base64 तब है जब चैनल सिर्फ़ टेक्स्ट वाला हो। - हेप का बिल: एन्कोडेड स्ट्रिंग JavaScript हेप में UTF-16 है, हर चर के लिए दो बाइट्स, और डिकोड किया हुआ या स्रोत Buffer डेटा की दूसरी पूरी कॉपी है। 100 MB फ़ाइल के लिए एक पल के लिए लगभग 270 MB स्ट्रिंग प्लस 100 MB Buffer। बड़ी को स्ट्रीम कीजिए, और एन्कोडेड रूप को उतनी देर ही रिफ़रेंस में रखिए जितना कोड अनुमति दे।
- Node के लीगेसी ग्लोबल्स: Node का अपना दस्तावेज़ीकरण
btoa()औरatob()को Stability 3, Legacy चिह्नित करता है, औरBufferइस्तेमाल करने की सलाह देता है। ब्राउज़र मेंbtoa()ASCII टेक्स्ट के लिए बिल्कुल ठीक टूल है; Node.js में Buffer की तरफ हाथ बढ़ाइए, और ग्लोबल्स को उन पॉलीफिल-आकार के कोड के छोड़ दीजिए जो उन्हें चाहिए।
JavaScript ने बाइट्स पैक करना कैसे सीखा
ब्राउज़र की तरफ की कहानी लंबी और खामोश है। btoa() की स्पेसिफिकेशन 2011 की शुरुआत में HTML5 ड्राफ्ट में हुई, और वह मिड-2000s से हर बड़े ब्राउज़र में बैठे आ रहा है, व्यवहार में बिना बदले, अपने एक-बाइट-प्रति-चर वादे के साथ और हमेशा-पैडेड आउटपुट के साथ। वह वादा टाइप्ड एरे से पहले का है - 2009 से पहले बाइट्स ले जाने का एकमात्र रास्ता बिनरी स्ट्रिंग्स थीं - इसलिए btoa() आज भी "बिनरी स्ट्रिंग्स" में सोचता है। कहानी का आधुनिक हिस्सा बहुत नया है: TC39 प्रोपोज़ल जिसने टाइप्ड एरे को नेटिव Base64 (hex समेत) मिलाया, ES2026 का हिस्सा बनकर स्टैंडरडाइज़ हुआ, और 2024 में Firefox 133 और Safari 18.2 में उतरा, 2 सितंबर 2025 को Chrome 140 में, और उसके बाद Baseline Newly available घोषित किया गया। Bun ने वही मेथड्स वर्ज़न 1.1.22 में, अगस्त 2024 में, रिलीज़ किए।
Node.js ने बाइट्स पैक करना एक अलग घड़ी पर सीखा। Buffer क्लास वर्ज़न 0.1.103 में ग्लोबल बन गई, 2010 के गर्मियों में, Node 1.0 से करीब पाँच साल पहले, और toString('base64') एक दशक से ज़्यादा तक एन्कोडर की पसंदीदा रही, उस दौर की वर्णमाला की विचित्रताओं के साथ (वह डिकोडिंग में URL-सुरक्षित चर पहले से ही मानी थी, एक द्विभाषी आदत जिसकी स्पेसिफ़िकेशन ने कभी माँग नहीं की)। जनवरी 2021 की वर्ज़न 15.7.0 ने 'base64url' मोड को पहली कतार की एन्कोडिंग नाम के तौर पर जोड़ा, उसी साल Node 16 ने ब्राउज़र के btoa()/atob() ग्लोबल्स जोड़े (तुरंत Legacy चिह्नित), और 2024 के Node 22 ने और V8 व base64 परफ़ॉर्मेंस काम निकाला। फिर Node 25, 15 अक्टूबर 2025 को रिलीज़, ने V8 को 14.1 तक बढ़ाया और ES2026 मेथड्स लाए, toBase64() उसके omitPadding ऑप्शन के साथ और दूसरी दिशा के लिए setFromBase64(), रनटाइम के अंदर। जो रनटाइम्स पीछे रह जाएँ, उनके लिए core-js पॉलीफिल निकालता है (features/typed-array/to-base64 / from-base64), और छोटा सा base64-js पैकेज (तीन फ़ंक्शन, शून्य डिपेंडेंसी) सालों से ट्रांज़िटिव डिपेंडेंसी के तौर पर इकोसिस्टम को चुपचाप संभालता आ रहा है।
जो फ़ॉर्मेट वे संभालते हैं वह इन सबसे पुराना है। वर्णमाला पहली बार 1987 में Privacy-Enhanced Mail के लिए स्टैंडरडाइज़ हुई (RFC 989), 1993 की रिवीजन (RFC 1421) ने उसे बरक़रार रखा, और उसी साल कुछ महीनों बाद MIME ने उसे अपनाया, अपने 76-चर रैप के साथ; RFC 3548 ने 2003 में Base-N परिवार को मिलाया और URL-सुरक्षित किस्म जोड़ी, जिसे RFC 4648 ने 2006 में दोबारा जारी किया। एक दशक बाद, RFC 7515 और 7519 ने बिना पैडिंग वाले base64url को हर JWT की रीढ़ बना दिया, और RFC 7636 ने उसे OAuth के PKCE फ़्लो में रख दिया। इस लेख के एन्कोडर उसी फ़ॉर्मेट का आख़िरी मील हैं जो तीस साल पुराना है और आज भी नए यात्री जोड़ रहा है।
पार्टी पर बताने लायक़
btoa('GIF89a')"R0lGODlh"लौटता है, एक GIF के पूरे मैजिक हेडर का आठ चरों में। यह सबसे छोटा "हैलो" है जो बाइनरी फ़ाइल Base64 में बोल सकती है, और इसीलिए यह Wikipedia लेख में Web API का पहला उदाहरण है।toBase64()का एकomitPaddingऑप्शन है जोbtoa()के पास कभी हो ही नहीं सकता, क्योंकि Web API का वादा बिना शर्त पैडिंग करता है। उसी वर्णमाला के दो दशक, और नई API वही एक चीज़ कर सकती है जो पुरानी को कभी मंज़ूर नहीं हुई।- एक वर्णमाला, दो आधिकारिक लाइन लेंथ: MIME 76 पर रैप करता है, PEM 64 पर। वही 64 अक्षर, वही पैडिंग, लाइन टेक्स्ट कितनी चौड़ी हो सकती है इस पर दो अलग 30 साल पुरानी रायें।
- 33 फ़ीसदी वाला अंक सही है: तीन बाइट्स पर चार चर 4/3 अनुपात है, और RFC-एरा ईमेल ने लाइन ब्रेक्स के लिए करीब 3.5 फ़ीसदी और जोड़ी। आपकी "छोटी" कॉन्फ़िग स्ट्रिंग बिना कुछ के 37 फ़ीसदी मोटी हो चुकी है।
- छोटा सा
base64-jsपैकेज npm पर हर हफ़्ते 10 करोड़ से ज़्यादा डाउनलोड ले जाता है, ज़्यादातर हिस्सा दूसरे पैकेजों की डिपेंडेंसी ट्रीज़ के अंदर छिपा हुआ। Base64 JavaScript इकोसिस्टम में सबसे ज़्यादा छुपकर भेजा गया कोड है। - छोटे Buffers को एक-एक करके एलोकेट नहीं किया जाता: Node उन्हें एक साझा 65536-बाइट पूल (
Buffer.poolSize) से काटता है, इसीलिए Buffer बनाना तेज़ है, और इसीलिए "अनसेफ़" एलोकेशन किस्में उन मामलों के लिए मौजूद हैं जहाँ पिछले किरायेदार का डेटा मायने रखता नहीं। - 1998 का वह RFC जो data URLs की व्याख्या करता है, चेतावनी देता है कि वे "सिर्फ़ छोटे मानों के काम आते हैं", 1024-चर HTML एट्रिब्यूट सीमा का हवाला देते हुए। मॉडर्न ब्राउज़र वही एट्रिब्यूट्स में मेगाबाइट-आकार की इमेज data URLs के तौर पर सहेजते हैं, जो या तो प्रगति है या घमंड, आपकी हीरो इमेज पर निर्भर।
- Unix पासवर्ड हैश अपनी-अपनी Base64-स्वरूप वर्णमालाएँ इस्तेमाल करते हैं, बिना पैडिंग के, और उलझन यह है कि क्रमबद्धता स्कीम अनुसार अलग है: क्लासिक
crypt(3)हैश./0-9A-Za-zइस्तेमाल करते हैं, जबकि JavaScript प्रोजेक्ट्स यूज़र पासवर्ड्स के लिए सहेजते हैं$2b$bcrypt स्ट्रिंग्स वही 64 अक्षर./A-Za-z0-9में घुमा देती हैं। यह अच्छी याद दिलाती है कि सुरक्षा के संदर्भ में "Base64" एक परिवार है, कोई एकल फ़ॉर्मेट नहीं। - Node का डिकोडर
'base64'और'base64url'दोनों मोड्स में-,_,+और/मानता है, चार चर, एक टेबल। एन्कोडर, बहरहाल, सिर्फ़ वही बोली बोलता है जो आपने माँगी है।
राउंड ट्रिप का आधा हिस्सा
JavaScript और Node.js में Base64 एन्कोड करना तीन फैसलों पर आकर रुकता है: आपके पास कौन से बाइट्स हैं (स्ट्रिंग को कैरेक्टर सेट चाहिए, Buffer को नहीं), मंज़िल कौन सी वर्णमाला माँगती है (MIME और data URLs के लिए क्लासिक, टोकन और URL के लिए base64url, पैडिंग संदर्भ पर वैकल्पिक), और फ़ॉर्मेट आज भी कौन से लाइन नियम लागू करता है (ईमेल के लिए 76, PEM के लिए 64, JSON के लिए कोई नहीं)। इनका जवाब दीजिए और बिल्ट-इन बाकी संभाल लेते हैं: Node में Buffer.toString(), ब्राउज़र में btoa() प्लस UTF-8 पुल, और उन आधुनिक रनटाइम्स में Uint8Array.toBase64(), जिनको अंततः यह मिला।
और जो हर पैकेज आप यहाँ सील करते हैं, कोई न कोई एक दिन खोलेगा। डिकोडिंग की तरफ के अपने-अपने फँदे हैं: वह दयालु डिकोडर जो कचरा बिना आवाज़ के निगल लेता है, वह बिनरी-स्ट्रिंग कपड़ा जो atob() आपको थमाता है, कैरेक्टर सेट के फैसले जो दीवार के पढ़ने वाले सिरे पर होते हैं, और वह स्ट्रीमिंग लॉजिक जो उसी कैरी पैटर्न की प्रतिकृति है जो आपने अभी सीखा है। वह कहानी, हर कदम के कोड उदाहरणों के साथ, हमारी बहन साइट के संबंधित Base64 डिकोडिंग लेख में विस्तार से कवर की गई है। उसे अगला पढ़िए, क्योंकि वर्णमाला की उस तरफ के फँदे चुपचाप हैं, और चुपचाप होना ही उनके जीतने का तरीका है।
अंतिम अपडेट: 2026-09-08
संबंधित लेख: JavaScript/Node.js में Base64 डिकोडिंग: एक सम्पूर्ण गाइड