क्या आपको Base64 फ़ॉर्मेट के साथ काम करना होता है? तो यह साइट आपके लिए एकदम सही है! अपने डेटा को एन्कोड या डिकोड करने के लिए, हमारे बेहद आसान ऑनलाइन टूल का इस्तेमाल करें।

Go में Base64 डिकोडिंग: एक सम्पूर्ण गाइड

एक API रेस्पॉन्स में छिपी एक लंबी स्ट्रिंग है, जो सिर्फ़ एक मान बने रहने का नाक़ दिखाती है, जबकि वह असल में एक फ़ाइल, टोकन, इमेज, या आपके सिस्टम से तीन साल बूढ़े किसी सिस्टम की मैसेज है। आपके लॉग लाइनों, डेटाबेस रो और JSON पेयलॉड्स में base64 स्ट्रिंग्स लगातार सामने आती रहती हैं: 64-चरों वाली स्टैंडर्ड वर्णमाला, कभी प्लस और स्लैश के साथ, कभी डैश और अंडरस्कोर के साथ, और कभी-कभी आख़िर में साइनचर की तरह पार्क किए हुए दो इक्वल्स चिह्न के साथ।

इस साइट का होम पेज फ़ॉर्मेट को पहले से ही समझा चुका है: 64 छापने योग्य चर, जिनमें से हर एक 6 बिट्स उठाता है, हर तीन इनपुट बाइट्स पर चार चर, और काम पूरा करने के लिए पैडिंग। इसलिए यह आर्टिकल सीधे उस आधे काम पर जाता है जहाँ रोचक फैसले होते हैं: इन स्ट्रिंग्स को Go में खोलना। अच्छी बात यह है कि Go इसे करने के लिए एक शानदार जगह है: एक स्टैंडर्ड लाइब्रेरी पैकेज, बिना किसी निर्भरता के, एक डिकोडर जो डिफ़ॉल्ट में सख़्त है पर न्यूलाइन्स के आगे सहिष्णु, और एरर मैसेज जो उसी बाइट पर उंगली उठाते हैं जहाँ ग़लती हुई।

Go के साथ क्या शिप होता है

जो कुछ भी चाहिए वह पहले से ही स्टैंडर्ड लाइब्रेरी में है। पैकेज का नाम encoding/base64 है, इसकी source फ़ाइल अभी भी 2009 का कॉपीराइट हेडर पहने हुई है, यानी वही साल जब भाषा जन्मी थी, और कोई एक्सटेंशन चालू करने को नहीं, कोई मॉड्यूल fetch करने को नहीं, कोई सेटिंग बदलने को नहीं। अगर go version आपकी मशीन पर कुछ भी प्रिंट करता है, तो पूरा टूल आपके हाथ में पहले से है।

लिखने के समय नवीनतम रिलीज़ Go 1.27.1 है, जो 1 सितंबर 2026 को आया, और दूसरी सपोर्टेड ट्रैक Go 1.26 लाइन है (वर्तमान में 1.26.8)। दोनों पर base64 API बिल्कुल एक जैसा है, और Go 1 की compatibility promise के चलते, आज base64 डिकोड करने वाला प्रोग्राम हर आने वाली रिलीज़ पर बिल्कुल वही करता रहेगा। Go खुद go.dev/dl की आधिकारिक टारबॉल से पाइए (जैसे go1.27.1.linux-amd64.tar.gz, जिसे /usr/local में unpack किया जाए), अपनी डिस्ट्रीब्यूशन के पैकेज मैनेजर से (Ubuntu-based सिस्टम पर sudo apt install golang-go), या कई Go वर्ज़न एक साथ रखने के शौक़ीन हैं तो golang.org/dl रैपर के ज़रिए।

Go इंस्टॉल हो चुके, go doc encoding/base64 पूरा API एक पढ़ने योग्य कॉलम में प्रिंट करता है, जो अपनी याददश्ती ताज़ा करने का सबसे तेज़ तरीका है। इस आर्टिकल में कहीं भी इस्तेमाल होने वाला एकमात्र अड-ऑन golang.org/x/text है, पुराने चैरसेट के लिए, और इसे go get golang.org/x/text से इंस्टॉल किया जाता है। वह सिर्फ़ एक बार आता है, अपने खुद के सेक्शन में, और बाकी सब शुद्ध स्टैंडर्ड लाइब्रेरी है।

आपका पहला डिकोड

Go में डिकोडिंग के काम का 90 फ़ीसद हिस्सा Encoding टाइप पर एक ही मेथड है:

func (enc *Encoding) DecodeString(s string) ([]byte, error)

इसे base64 स्ट्रिंग दें, तो वह जो बाइट्स वह दर्शाता है उन्हें वापस देता है, और जब इनपुट मज़ाक करे तो एक एरर भी:

package main

import (
  "encoding/base64"
  "fmt"
)

func main() {
  decoded, err := base64.StdEncoding.DecodeString("TWFu")
  if err != nil {
    fmt.Println("decode failed:", err)
    return
  }
  fmt.Println(string(decoded)) // Man
}

उस signature के बारे में दो बातें याद रखने लायक़ हैं। पहली, नतीजा []byte होता है, स्ट्रिंग नहीं, क्योंकि आपके खोले बाइट्स बिल्कुल वैध base64 हो सकते हैं और बिल्कुल बेकाम टेक्स्ट: PNG हेडर, संपीड़ित आर्काइव, बाइनरी प्रोटोकॉल। उसे string(...) में व्रैप तभी करें जब आपको पक्का पता हो कि पेयलॉड टेक्स्ट है। दूसरी, मेथड हमेशा दो मान लौटाता है। nil एरर का मतलब है स्ट्रिंग साफ़ base64 थी; non-nil एरर का मतलब है इनपुट कहीं टूटी हुई थी, और जो बाइट स्लाइस आपको मिली है वह ख़ाली की जगह एक आधा नतीजा हो सकता है। उस व्यवहार के दोनों पहलू आप नीचे के एरर सेक्शन में देखेंगे।

चार डिकोडर, एक सवाल: कौन-सी वर्णमाला?

Go चार तैयार Encoding values शिप करता है, और सही एक चुनना हर डिकोड का पहला असली फैसला है। नीचे की टेबल सीटिंग चार्ट है:

वैरिएबल वर्णमाला पैडिंग कहाँ मिलेगा
StdEncoding A-Z a-z 0-9 + / = MIME ईमेल, data URLs, HTTP Basic auth, PEM फ़ाइलें, सामान्य JSON
URLEncoding A-Z a-z 0-9 - _ = URL के paths और queries, फ़ाइल-नाम
RawStdEncoding A-Z a-z 0-9 + / कोई नहीं कॉम्पैक्ट उत्पादक से आया बिना-पैडिंग स्टैंडर्ड base64
RawURLEncoding A-Z a-z 0-9 - _ कोई नहीं JWT सेगमेंट, कॉम्पैक्ट API पहचान-चिह्न

चुनने का सबसे तेज़ तरीका यह है कि डेटा खुद को देखें। + या / वाली स्ट्रिंग केवल स्टैंडर्ड वर्णमाला की स्ट्रिंग हो सकती है, इसलिए उसे दो Std डिकोडरों में से एक चाहिए। - या _ वाली स्ट्रिंग RFC 4648 की URL-safe variant है, इसलिए उसे दो URL डिकोडरों में से एक चाहिए। फिर स्ट्रिंग के आख़िर को देखें: आख़िर में = चर होने का मतलब है पैडिंग वाला variant, और उनकी अनुपस्थिति का मतलब है Raw वाला। ग़लत चुनाव कैसा लगता है, यहाँ देखें:

decoded, err := base64.StdEncoding.DecodeString("P29_")
// err: illegal base64 data at input byte 3
// अंडरस्कोर स्टैंडर्ड वर्णमाला में नहीं है, इसलिए
// डिकोडर उस आख़िरी चर पर रुक जाता है जो वह पहचानता नहीं
decoded, err = base64.URLEncoding.DecodeString("P29_")
// decoded तीन बाइट्स 0x3f 0x6f 0x7f है, err nil है

अगर आप किसी उत्पादक के डेटा को डिकोड कर रहे हैं जिसने खुद की 64-चरों वाली वर्णमाला तय की है, तो base64.NewEncoding("...64 chars...") उसके लिए आपको डिकोडर बना देता है। वर्णमाला में ठीक 64 अलग-अलग बाइट मान होनी चाहिए और कोई न्यूलाइन नहीं - वरना फ़ंक्शन पैनिक कर देता है - दस्तावेज़ीकरण वर्णमाला से पैडिंग चर को बाहर रखने की मांग करता है, पर फ़ंक्शन वह enforce नहीं करता - '=' वाली वर्णमाला बिना पैनिक के स्वीकार हो जाती है। रोज़मर्रा के काम में आपको यह ज़्यादातर नहीं चाहिए, पर यह मौजूद है, और यह किसी निजी स्कीम को डिकोड करने का एकमात्र राह है।

सहिष्णुता का मुद्दा: Go कौन-सा इनपुट स्वीकार करता है?

हर base64 डिकोडर को एक असहज फैसला करना पड़ता है: वह कितना कचरा निगलने को तैयार है? Go का जवाब एक सावधानी से खींची हुई लाइन है। सहिष्णु पक्ष पर, डिकोडर इनपुट में कहीं भी carriage returns और line feeds को छोड़ देता है, इसलिए ऐसी स्ट्रिंग जो किसी ईमेल क्लाइंट या PEM टूल ने कई लाइनों में बाँट दी हो, बिना किसी प्री-प्रोसेसिंग के डिकोड हो जाती है:

decoded, err := base64.StdEncoding.DecodeString("T\nW\nF\r\nu")
// decoded "Man" है, err nil है
// स्ट्रिंग के हर \r और \n को बस नज़रअंदाज़ किया गया

सख़्त पक्ष पर, बाकी सब से बाहर है। एक स्पेस, एक टैब, PDF से कॉपी किया गया ज़ीरो-विड्थ चर, किसी हेडर से चली आई एक भटकती कॉलन: उसी पल जब डिकोडर ऐसे चर से मिलता है जो न वर्णमाला में है और न न्यूलाइन, वह रुक जाता है और ऑफ़सेट report करता है। और जो कुछ वह पहले से डिकोड कर चुका था, वह रख लेता है:

decoded, err := base64.StdEncoding.DecodeString("TWFu junk")
// decoded "Man" है (space से पहले का हिस्सा),
// err है: illegal base64 data at input byte 4

यह जोड़ी लोगों को चौंकाती है: एक फ़ेल डिकोड भी आपको इस्तेमाल के लायक़ आधा-नतीजा दे सकती है। वह फ़ीचर है या ख़तरा, यह आप पर निर्भर करता है; बात यह है कि err == nil ही वह एकमात्र स्थिति है जिसमें डेटा पूरा होता है।

पैडिंग के अपने नियम हैं, और वे पैडिंग वाले और raw variants में अलग-अलग हैं। पैडिंग वाले डिकोडर ग्रुप में काम करते हैं: एक ग्रुप या तो चार असली चर होता है, या दो असली चरों के बाद ==। एक चर अकेला कभी पूरा ग्रुप नहीं होता, इसलिए "T" फेल होता है, और "TWF" भी फेल होता है, क्योंकि तीन चरों को एक ऐसा पैडिंग साइन चाहिए जो ग़ायब है। Raw डिकोडर पैडिंग की ज़रूरत छोड़ देते हैं, पर वे उस लंबाई को स्वीकार नहीं कर सकते जहाँ ग्रुप के चारों चरों में से तीन ग़ायब हों, इसलिए "T" वहाँ भी फेल होता है, जबकि "TW" खुशी-खुशी एकल बाइट में डिकोड हो जाता है।

base64.StdEncoding.DecodeString("T")        // इनपुट बाइट 0 पर एरर
base64.StdEncoding.DecodeString("TWF")      // इनपुट बाइट 0 पर एरर
base64.RawStdEncoding.DecodeString("TW")    // 1 बाइट, एरर नहीं
base64.StdEncoding.DecodeString("TWFu====") // "Man" और बाइट 4 पर एरर

एक और मूड स्विच है: Strict(), जो Go 1.8 में जुड़ा। Strict मोड में डिकोडर RFC 4648 सेक्शन 3.5 के कैनोनिकल फ़ॉर्म को enforce करता है: आख़िरी ग्रुप के बेकार ट्रेलिंग बिट्स को शून्य होना चाहिए। Normal मोड को इसका मतलब नहीं, क्योंकि उन बिट्स का इस्तेमाल बस कभी नहीं होता, इसलिए "Qm==" बिना शिकायत के बाइट B में डिकोड होता है। Strict मोड इसके बजाय इसे रिजेक्ट कर देता है:

decoded, err := base64.StdEncoding.DecodeString("Qm==")
// decoded "B" है, err nil है (आख़िरी बिट्स छोड़े गए)
decoded, err = base64.StdEncoding.Strict().DecodeString("Qm==")
// err है: illegal base64 data at input byte 2

ध्यान दें कि strict मोड में भी न्यूलाइन्स अभी भी छोड़े जाते हैं, जैसा दस्तावेज़ीकरण की ओर इशारा करता है। Strict() तभी इस्तेमाल करें जब आप ऐसा प्रोटोकॉल बोल रहे हों जो कैनोनिकल एन्कोडिंग का ख़याल रखता है, या जब आप असावधान उत्पादक को ख़ामोशी से निगल लेने के बजाय रिजेक्ट करना चाहते हों।

ऐसे एरर जो बताते हैं कि कहाँ

इस पैकेज में हर विफलता एक स्पष्ट, जाँचने योग्य मान के रूप में आती है। जब इनपुट में कुछ ऐसा हो जो वर्णमाला को न पता हो, या पैडिंग ग़लत हो, तो डिकोडर base64.CorruptInputError लौटाता है, और उसकी मैसेज में समस्या की बाइट ऑफ़सेट शामिल होती है:

type CorruptInputError int64

func (e CorruptInputError) Error() string {
  return "illegal base64 data at input byte " + strconv.FormatInt(int64(e), 10)
}

वही ऑफ़सेट "कुछ गिर गया" और "इस 900-किलोबाइट स्ट्रिंग का 4,102वाँ चर एक टैब है जो क्लिपबोर्ड से भटककर आ गया" के बीच का फ़र्क़ है। इसे Go के आम आइडियम से पकड़ें:

package main

import (
  "encoding/base64"
  "errors"
  "fmt"
)

func main() {
  _, err := base64.StdEncoding.DecodeString("TWF$")
  var corrupt base64.CorruptInputError
  if errors.As(err, &corrupt) {
    fmt.Printf("bad byte at offset %d: %v\n", int(corrupt), err)
    // bad byte at offset 3: illegal base64 data at input byte 3
    return
  }
  fmt.Println("not a corrupt-input error:", err)
}

जो इनपुट लोगों को सबसे ज़्यादा भ्रमित करते हैं, उनके लिए यहाँ लक्षण चार्ट है:

इनपुट (StdEncoding) नतीजा क्यों
TWF$ बाइट 3 पर एरर $ वर्णमाला में नहीं है
T बाइट 0 पर एरर एक चर कभी पूरा ग्रुप नहीं होता
TWF बाइट 0 पर एरर तीन चरों को एक = चाहिए जो ग़ायब है
TWFu junk Man साथ में बाइट 4 पर एरर स्पेस न्यूलाइन नहीं है, इसलिए डिकोडिंग वहीं रुक जाती है
TWFu\t Man साथ में बाइट 4 पर एरर टैब स्किप नहीं होते, सिर्फ़ \r और \n
T\nW\nF\nu Man, एरर नहीं न्यूलाइन्स कहीं भी नज़रअंदाज़ किए जाते हैं
==== बाइट 0 पर एरर ग्रुप की शुरुआत में पैडिंग वैध नहीं है
(खाली string) खाली नतीजा, एरर नहीं शून्य बाइट्स base64 शून्य बाइट्स में डिकोड होते हैं

एक अमली सुझाव: जब प्रोडक्शन में डिकोड फेल हो, तो ऑफ़सेट और उसके आस-पास का छोटा विंडो लॉग करें। 90 फ़ीसद बार वह "ख़राब" बाइट एक व्हाइटस्पेस है जो ट्रांसपोर्ट, क्लिपबोर्ड, या PDF व्यूअर ने स्ट्रिंग में छुपाकर रखा है, और सुधार एक ट्रिम या स्ट्रिप है, न कि पुनर्-डिज़ाइन।

फ़ाइलें खोलना

Base64 फ़ाइलें बस टेक्स्ट फ़ाइलें हैं जिनमें base64 होता है, इसलिए Go के आम फ़ाइल टूल्स यहाँ लागू होते हैं। जो फ़ाइल मेमोरी में आराम से बैठ जाए, उसे पूरा पढ़ लें और स्ट्रिंग को डिकोड करें:

package main

import (
  "encoding/base64"
  "fmt"
  "io"
  "os"
)

func main() {
  f, err := os.Open("payload.b64")
  if err != nil {
    fmt.Println("open failed:", err)
    return
  }
  defer f.Close()

  raw, err := io.ReadAll(f)
  if err != nil {
    fmt.Println("read failed:", err)
    return
  }
  decoded, err := base64.StdEncoding.DecodeString(string(raw))
  if err != nil {
    fmt.Println("decode failed:", err)
    return
  }
  fmt.Println("decoded", len(decoded), "bytes")
}

बड़ी फ़ाइलों के लिए बेहतर पैटर्न स्ट्रीमिंग है, और वह पैकेज API के दूसरे हिस्से का इस्तेमाल करता है: NewDecoder किसी भी io.Reader को base64-डिकोडिंग रीडर में व्रैप करता है, ताकि आप फ़ाइल से फ़ाइल pipe कर सकें बिना पूरे पेयलॉड को कभी मेमोरी में पकड़े:

in, err := os.Open("payload.b64")
if err != nil {
  panic(err)
}
defer in.Close()

dec := base64.NewDecoder(base64.StdEncoding, in)
out, err := os.Create("payload.bin")
if err != nil {
  panic(err)
}
defer out.Close()

written, err := io.Copy(out, dec)
if err != nil {
  panic(err)
}
fmt.Println("wrote", written, "bytes")

जब आप वह अतिरिक्त अलोकेशन टालना चाहें जो DecodeString करता है, तब एक बीच का ऑप्शन है: Decode एक गंतव्य बफ़र में लिखता है जिसे आप खुद नियंत्रित करते हैं। DecodedLen से उसे साइज़ दें, जो एक दिए गए इनपुट लंबाई के लिए अधिकतम आउटपुट बाइट्स की संख्या लौटाता है:

raw, err := os.ReadFile("payload.b64")
if err != nil {
  panic(err)
}
buf := make([]byte, base64.StdEncoding.DecodedLen(len(raw)))
n, err := base64.StdEncoding.Decode(buf, raw)
if err != nil {
  panic(err)
}
data := buf[:n] // असली डिकोड साइज़
fmt.Println(len(data), "bytes")

फिर भी, उस आख़िरी वाले के साथ सावधानी बरतें: Decode बफ़र का साइज़ देने में आप पर भरोसा करता है। अगर वह बहुत छोटा है, तो मेथड एरर लौटाता नहीं है; वह index out of range के साथ पैनिक कर देता है। DecodedLen ही वही आँकड़ा है जिसका इस्तेमाल करना है, len(raw) नहीं।

Go के लिए एक Base64 कमांड लाइन

Unix सिस्टम coreutils के साथ एक base64 यूटिलिटी शिप करते हैं, और Go कोई समतुल्य बाइनरी शिप नहीं करता। Go की दुनिया में आइडियमैटिक जवाब वह पैकेज नहीं जो आप इंस्टॉल करते हैं, बल्कि वह प्रोग्राम है जो आपका अपना होता है: एक छोटा कमांड-लाइन टूल, encoding/base64, flag पैकेज और स्टैंडर्ड इनपुट के चारों ओर बना। यहाँ एक पूरा है, करीब चालीस लाइन का, जो जो कुछ भी pipe होकर आया है उसे डिकोड करता है और raw बाइट्स बाहर लिखता है:

package main

import (
  "encoding/base64"
  "flag"
  "fmt"
  "io"
  "os"
)

func main() {
  urlSafe := flag.Bool("url", false, "use the URL-safe alphabet")
  flag.Parse()

  enc := base64.StdEncoding
  if *urlSafe {
    enc = base64.URLEncoding
  }

  raw, err := io.ReadAll(os.Stdin)
  if err != nil {
    fmt.Fprintln(os.Stderr, "read failed:", err)
    os.Exit(1)
  }
  decoded, err := enc.DecodeString(string(raw))
  if err != nil {
    fmt.Fprintln(os.Stderr, "decode failed:", err)
    os.Exit(1)
  }
  os.Stdout.Write(decoded)
}

इसे एक बार go build -o b64 . से बना लें और वह एक क्रॉस-प्लेटफ़ॉर्म डिकोडर बन जाता है जिसे आप Makefile, CI पाइपलाइन या शेल फ़ंक्शन में रख सकते हैं: printf 'TWFu' | ./b64 Man प्रिंट करता है, और ./b64 -url < token.b64 > token.bin एक URL-safe टोकन को unwrap करके फ़ाइल में डाल देता है। इस डिज़ाइन की दो ख़ूबियाँ ध्यान देने लायक़ हैं। क्योंकि वह डिकोड से पहले पूरा stdin पढ़ लेता है, इसलिए न्यूलाइन्स वाले wrapped इनपुट डिकोड होकर ठीक रहता है, डिकोडर की न्यूलाइन सहिष्णुता के दम पर। और क्योंकि वह ग़लत इनपुट पर स्टेटस 1 के साथ exit करता है और शिकायत stderr में लिखता है, वह पाइपलाइन में एक टूल की तरह व्यवहार करता है, न कि एक ऐसे स्क्रिप्ट की जो माफ़ी माँगता हो। यही Go CLI का पूरा कला है: एक पैकेज, एक फ़्लैग, stdin, stdout, और एक exit कोड।

URL-Safe डिकोडिंग

URL-safe variant इसलिए मौजूद है क्योंकि स्टैंडर्ड वर्णमाला URL के व्याकरण से टकराती है: query स्ट्रिंग्स में + को अक्सर स्पेस पढ़ा जाता है, और / नया path सेगमेंट शुरू करता है, इसलिए URL में बसाए गए स्टैंडर्ड base64 स्ट्रिंग को चर-दर-चर पर्सेंट escape करना पड़ता है, जो parse करने में धीमा और पढ़ने में बदसूरत होता है। RFC 4648 की वैकल्पिक वर्णमाला + और / की जगह - और _ रख देती है, जो दोनों URL के paths, queries और फ़ाइल-नाम में बिना escape के वैध हैं।

Go में यह स्विच बस एक अलग डिकोडर वैरिएबल है। अगर आपका डेटा URL-safe और पैडिंग वाला है, तो URLEncoding इस्तेमाल करें; URL-safe और बिना-पैडिंग हो तो RawURLEncoding। क्लासिक केस है ऐसी पहचान जो URL या फ़ाइल-नाम में रहती है:

decoded, err := base64.RawURLEncoding.DecodeString("-w9n")
// decoded तीन बाइट्स 0xfb 0x0f 0x67 है
// डैश और अंडरस्कोर URL-safe वर्णमाला के हिस्से हैं,
// इसलिए RawURLEncoding वहाँ उनसे निपटता है जहाँ StdEncoding फेल हो जाता

असली Go कोड में कहाँ मिलेगा: JWT सेगमेंट (अगले में कवर), ओपेक पहचान-चिह्न जो सिस्टम बनाकर URLs में store करते हैं, फ़ाइल-नाम जो किसी वेब सर्वर या क्लाउड ऑब्जेक्ट store को नहीं तोड़ सकते, और कोई भी API जिसने अपनी दस्तावेज़ीकरण में "base64url" का वादा किया हो। एक चेतावनी: URL-safe उत्पादक और उपभोक्ता के बीच का अनुबंध है, डेटा की ख़ूबी नहीं। अगर स्ट्रिंग में + या / है, तो वह URL-safe नहीं है, ख़त्म बात, और URL डिकोडर से कितने भी retry करने से कोई मदद नहीं होगी। पहले चर देखें, फिर डिकोडर चुनें।

JWT के अंदर झाँकना

JSON Web टोकन तीन base64url सेगमेंट हैं, जो डॉट्स से अलग-अलग हैं: एक हेडर, claims का पेयलॉड, और एक साइनचर, और किसी भी सेगमेंट में कोई पैडिंग नहीं। इसीलिए JWT Go में डिकोड करने वाली सबसे आम चीज़ों में से एक है, और हेडर और पेयलॉड बिना किसी key के पढ़े जा सकते हैं, जो बात डिबगिंग के लिए भी याद रखने लायक़ है और सिक्योरिटी रिव्यू के लिए भी:

package main

import (
  "encoding/base64"
  "fmt"
  "log"
  "strings"
)

func main() {
  token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiR28gRGV2ZWxvcGVyIiwic3ViIjoiMTIzNDU2Nzg5MCJ9.NwJQAKfJpMJQuK0gEECtXtO8cIoFnDp0ovXyl7dY1BQ"
  parts := strings.Split(token, ".")
  if len(parts) != 3 {
    log.Fatal("not a JWT: expected three dot-separated parts")
  }
  for i, name := range []string{"header", "payload"} {
    plain, err := base64.RawURLEncoding.DecodeString(parts[i])
    if err != nil {
      log.Fatalf("bad %s: %v", name, err)
    }
    fmt.Printf("%s: %s\n", name, plain)
  }
  // header:  {"alg":"HS256","typ":"JWT"}
  // payload: {"name":"Go Developer","sub":"1234567890"}
}

डिकोडर के चुनाव पर नज़र डालें: RawURLEncoding, StdEncoding नहीं। JWT सेगमेंट URL-safe वर्णमाला इस्तेमाल करते हैं और पैडिंग नहीं रखते, और ऐसा सेगमेंट जिसकी लंबाई चार के गुणज से एक या दो कम हो, पैडिंग वाले डिकोडर को आख़िर में ही फेल कर देता है, और भ्रमित करने वाला एरर पीछे करने में मुश्किल है। साइनचर सेगमेंट को बिना key के नहीं पढ़ सकते, और पेयलॉड के आधार पर किसी चीज़ पर भरोसा करने की कोशिश भी नहीं करनी चाहिए, क्योंकि क्लाइंट को पहले दो सेगमेंट नक़ली बनाने से कोई नहीं रोक सकता। जब आपको वेरिफिकेशन चाहिए, तब एक भरोसेमंद लाइब्रेरी इस्तेमाल करें। वास्तविक एक है github.com/golang-jwt/jwt/v5 (go get github.com/golang-jwt/jwt/v5 से इंस्टॉल करें):

package main

import (
  "fmt"
  "log"

  "github.com/golang-jwt/jwt/v5"
)

func main() {
  secret := []byte("hmac-secret")
  token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiR28gRGV2ZWxvcGVyIiwic3ViIjoiMTIzNDU2Nzg5MCJ9.NwJQAKfJpMJQuK0gEECtXtO8cIoFnDp0ovXyl7dY1BQ"

  parsed, err := jwt.Parse(token, func(t *jwt.Token) (any, error) {
    if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
      return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
    }
    return secret, nil
  })
  if err != nil {
    log.Fatal("token rejected:", err)
  }
  claims, _ := parsed.Claims.(jwt.MapClaims)
  fmt.Println("subject:", claims["sub"])
}

लाइब्रेरी की दो बातें जानने लायक़ हैं। पहली, तीन सेगमेंट का base64url एन्कोडिंग और डिकोडिंग अंदर से ही handle होती है, इसलिए आप साइन या वेरिफाई करते समय encoding/base64 को सीधे हाथ नहीं लगाते। दूसरी, v5 लाइब्रेरी alg=none वाले टोकन को रिजेक्ट कर देती है, जब तक कि आप उसके UnsafeAllowNoneSignatureType कॉन्स्टेंट को साफ़-साफ़ न पास करें, और यही आपको क्लासिक "अहस्ताक्षरित टोकन स्वीकार हो गया" ग़लती से बचाता है।

Data URLs

data URL वह URL है जिसका पेयलॉड डेटा खुद होता है। सिंटैक्स, RFC 2397 के अनुसार, data:[mediatype][;base64],data है: एक वैकल्पिक मीडिया टाइप, एक वैकल्पिक ;base64 फ़्लैग, एक comma, और फिर कंटेंट। जब ;base64 फ़्लैग मौजूद होता है, तो कंटेंट स्टैंडर्ड base64 होता है, और इसीलिए data URLs और यह आर्टिकल एक सेक्शन साझा करते हैं। ब्राउज़र इस्तेमाल करते हैं ताकि इमेज और फॉन्ट्स को HTML और CSS में सीधे embed करें, जिससे पेज को एक रिक्वेस्ट कम चाहिए:

<img src="data:image/png;base64,iVBORw0KGgo=" alt="pixel">

Go की स्टैंडर्ड लाइब्रेरी में data URL हेलपर नहीं है, पर फ़ॉर्मेट इतना साधारण है कि strings के साथ हाथ से parse किया जा सकता है, और यही अधिकांश Go प्रोग्राम करते हैं:

package main

import (
  "encoding/base64"
  "fmt"
  "strings"
)

func main() {
  url := "data:image/png;base64,iVBORw0KGgo="
  if !strings.HasPrefix(url, "data:") {
    fmt.Println("not a data URL")
    return
  }
  rest := url[len("data:"):]
  comma := strings.Index(rest, ",")
  if comma == -1 {
    fmt.Println("missing comma")
    return
  }
  meta := rest[:comma]      // image/png;base64
  encoded := rest[comma+1:] // iVBORw0KGgo=
  if !strings.HasSuffix(meta, ";base64") {
    fmt.Println("this variant is percent-encoded, not base64")
    return
  }
  mediaType := strings.TrimSuffix(meta, ";base64")
  decoded, err := base64.StdEncoding.DecodeString(encoded)
  if err != nil {
    fmt.Println("decode failed:", err)
    return
  }
  fmt.Println(mediaType, "carries", len(decoded), "bytes")
}

तीन फ़सेल याद रखने लायक़ हैं। पहली, ;base64 फ़्लैग वैकल्पिक है, और इसके बिना पेयलॉड base64 की जगह पर्सेंट-एन्कोड ASCII होता है, इसलिए डिकोडर कॉल करने से पहले सफ़िक्स जाँचें। दूसरी, जब मीडिया टाइप छोड़ा जाता है, तो डिफ़ॉल्ट text/plain;charset=US-ASCII होता है, जो इमेजों के लिए ज़्यादातर मतलब नहीं रखता, पर दूसरा कंटेंट parse करने वालों को चौंकाता है। तीसरी, data URLs छोटे पेयलॉड की तरिका है: RFC खुद कहता है कि स्कीम सिर्फ़ छोटे मान के लिए काम आता है, और base64 का 33 फ़ीसद साइज़ एक्सपन्शन एक 500-किलोबाइट लोगो को 666-किलोबाइट स्ट्रिंग बना देता है जो आपके HTML में चिपका हुआ रहता है - cache नहीं हो सकता, share नहीं हो सकता। इस्तेमाल आइकॉन और थंबनेल के लिए करें, वीडियो के लिए नहीं।

HTTP और API का काम

Go वेब सर्विस में सबसे आम डिकोड JSON बॉडी फील्ड है: अपलोड फ़ॉर्म, API रेस्पॉन्स, या webhook आपको एक स्ट्रिंग देता है जो असल में फ़ाइल है। एक struct में unmarshal करें, फिर फील्ड को डिकोड करें:

package main

import (
  "encoding/base64"
  "encoding/json"
  "fmt"
)

type payload struct {
  Avatar string `json:"avatar"`
}

func main() {
  body := []byte(`{"avatar": "iVBORw0KGgo="}`)
  var p payload
  if err := json.Unmarshal(body, &p); err != nil {
    fmt.Println("bad JSON:", err)
    return
  }
  img, err := base64.StdEncoding.DecodeString(p.Avatar)
  if err != nil {
    fmt.Println("bad avatar:", err)
    return
  }
  fmt.Println("avatar is", len(img), "bytes")
}

अगर आपका API स्टैंडर्ड और URL-safe दोनों स्ट्रिंग्स स्वीकार करता है, तो उपयोगी पैटर्न यह है: एक डिकोडर आज़माएँ, और अगर वह आख़िर के करीब CorruptInputError के साथ फेल हो जाए, तो हार मानने से पहले दूसरा आज़माएँ। यह आज़माइश एक से ज़्यादा बार न करें, और "इक्वल्स चिह्न हटा लो और उम्मीद रखो" को आम रणनीति की तरह कभी fallback न बनाएँ।

HTTP Basic ऑथेंटिकेशन के लिए आप कोई डिकोडिंग नहीं करते, क्योंकि Go आपके लिए कर देता है। Request.BasicAuth, जो Go 1.4 से उपलब्ध है, Authorization हेडर आपके लिए split कर देता है और यूज़रनेम व पासवर्ड लौटाता है, पहले से RFC 2617 द्वारा तय किए गए user:pass जोड़ी पर स्टैंडर्ड base64 डिकोडर चला चुका है:

package main

import (
  "fmt"
  "net/http"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) {
    user, pass, ok := r.BasicAuth()
    if !ok || user != "alice" || pass != "s3cret" {
      w.Header().Set("WWW-Authenticate", `Basic realm="api"`)
      w.WriteHeader(http.StatusUnauthorized)
      return
    }
    fmt.Fprintln(w, "hello", user)
  })
  http.ListenAndServe(":8080", mux)
}

याद रखें कि Basic auth ऑथेंटिकेशन है, सुरक्षा नहीं: हेडर base64 है, एन्क्रिप्टेड नहीं, इसलिए वह सिर्फ़ HTTPS के ऊपर ही सफ़र कर सकती है। अगर आप क्लाइंट हैं, तो उल्टी call req.SetBasicAuth(user, pass) है, जो स्टैंडर्ड एन्कोडर के साथ वही हेडर आपके लिए बना देता है।

API हैंडलर के लिए एक सावधानी भरी आदत: डिकोड से पहले बॉडी को लिमिट करें, http.MaxBytesReader या बराबर के लंबाई चेक के साथ। base64 स्ट्रिंग अपने लंबाई के करीब तीन-चौथाई में डिकोड होती है, इसलिए N बाइट्स की बॉडी लिमिट डिकोड नतीजा को N बाइट्स से नीचे रखती है, और मेमोरी सीमित ही रहती है, चाहे शत्रुतापूर्ण क्लाइंट जो भी post करे। असीमित बॉडी को डिकोड करना क्लासिक मेमोरी ख़त्म होने का वेक्टर है, क्योंकि हमलावर ही तय करता है कि कितने मेगाबाइट टेक्स्ट को बाइनरी में बदला जा सके।

पुराने चैरसेट

base64 को डिकोड करने से आपको बाइट्स मिलते हैं, और आधुनिक सिस्टम में वे बाइट्स ज़्यादातर हमेशा UTF-8 होते हैं, जिस स्थिति में string(decoded) ही पूरी कहानी है। पर base64 पुराना फ़ॉर्मेट है, और इसकी खूब सारी रचना ऐसे सिस्टम ने की है जो Windows-1252, ISO-8859-1, Shift JIS या कोई और एक-बाइट या दो-बाइट पुराने चैरसेट इस्तेमाल करते थे। अगर उत्पादक ने वैसा किया है, तो आपके डिकोड किए बाइट्स वैध UTF-8 नहीं हैं, और Go यह नक़ल नहीं करेगा: जहाँ कोई क्रम टूटा है, वहाँ वह आपको प्रतिस्थापन चरों दिखाएगा।

Go का जवाब golang.org/x/text मॉड्यूल है, जो आम चैरसेट के लिए पुराने-एन्कोड बाइट्स को UTF-8 में बदलता है (और वापस भी)। रूपांतरण की जगह डिकोड के ठीक बाद है, और वह सिर्फ़ एक फ़ंक्शन कॉल में होता है:

package main

import (
  "encoding/base64"
  "fmt"

  "golang.org/x/text/encoding/charmap"
  "golang.org/x/text/transform"
)

func main() {
  // "Café" किसी legacy tool ने Windows-1252 में store किया,
  // फिर transport के लिए base64-encode
  encoded := "Q2Fm6Q=="
  raw, err := base64.StdEncoding.DecodeString(encoded)
  if err != nil {
    fmt.Println("decode failed:", err)
    return
  }
  utf8, _, err := transform.Bytes(charmap.Windows1252.NewDecoder(), raw)
  if err != nil {
    fmt.Println("charset conversion failed:", err)
    return
  }
  fmt.Println(string(utf8)) // Café
}

मॉड्यूल में हर चैरसेट परिवार के लिए एक सबपैकेज है: Windows और ISO एक-बाइट टेबल के लिए charmap, Shift JIS और EUC-JP के लिए japanese, EUC-KR के लिए korean, GB18030 के लिए simplifiedchinese, और Big5 के लिए traditionalchinese। अनुभव का नियम यह है कि कन्वर्ट तभी करें जब आपको उत्पादक के चैरसेट का पक्का पता हो, क्योंकि UTF-8 बाइट्स को दूसरी बार कन्वर्ट करने से शोर-शराबा मचाते हुए फेल नहीं होता; वह बस टेक्स्ट को बर्बाद कर देता है। शक हो तो पेयलॉड को बाइट्स की तरह ही लेने दें और downstream उपभोक्ता को फ़ैसला करने दें।

स्ट्रीमिंग और chunked डिकोडिंग

आपने NewDecoder फ़ाइलें सेक्शन में देखा है; यहाँ वह बात है जिससे इसे अपना अलग सेक्शन मिलने का हक़ है। यह एक असली स्ट्रीमिंग एडैप्टर है: वह नीचे वाले रीडर से बस उतना ही खींचता है जितना चाहिए, आते ही उसी पल डिकोड करता है, और उसी पल जब स्ट्रीम ख़राब होती है CorruptInputError लौटाता है। पूरी स्ट्रीम टैराबाइट की हो सकती है; जो मेमोरी आप पकड़ते हैं वह आपका बफ़र और वह आउटपुट है जो आप लिखते हैं। दो आम उपभोक्ता पैटर्न हैं: छोटी स्ट्रीम्स के लिए io.ReadAll और बाकी सब के लिए io.Copy:

small, err := io.ReadAll(base64.NewDecoder(base64.StdEncoding, r))
// कॉन्फ़िग ब्लॉब या छोटे एटैचमेंट के लिए ठीक है

w, err := io.Copy(out, base64.NewDecoder(base64.StdEncoding, r))
// video, tarball, या restore job के लिए ठीक है

Go 1.22 से पैकेज में AppendDecode भी है, जो हर कॉल पर नई स्लाइस अलोकेट करने की बजाय आपके reuse किए बफ़र में डिकोड करता है। यह हॉट paths के लिए वाला टूल है जहाँ लूप में कई चंक्स डिकोड होते हैं, जैसे लाइन प्रोसेसर या प्रोटोकॉल डिकोडर:

var buf []byte
for _, chunk := range chunks {
  buf, err = base64.StdEncoding.AppendDecode(buf, chunk)
  if err != nil {
    return err
  }
  process(buf)
}

मेथड डिकोड चंक को buf में जोड़ता है (चाहे वह खाली हो या पहले से कुछ पकड़े), बढ़ा हुआ स्लाइस लौटाता है, ज़रूरत पड़ने पर backing array को बढ़ाते हुए। स्थिर स्टेट में, जहाँ बफ़र पहले से सही साइज़ तक बढ़ चुका होता है, यह हर चंक पर शून्य अलोकेशन करता है, जो बेन्चमार्क में साफ़ दिखता है। अगर आपका वर्कलोड "एक बार डिकोड, कभी-कभी" है, तो DecodeString आसान चुनाव है; अगर "tight लूप में हज़ारों बार डिकोड" है, तो AppendDecode ही वह है जिसका सहारा लें।

इसे सुरक्षित रखना

कुछ सिक्योरिटी नोट्स जो इस बात से जुड़े हैं कि Go प्रोग्राम इस पैकेज का असल काम में इस्तेमाल कैसे करते हैं। पहली, base64 एन्कोडिंग है, एन्क्रिप्शन नहीं। base64 स्ट्रिंग को किसी भी वेब ब्राउज़र के डेवलपर टूल्स से पढ़ सकता है, इसलिए "हम पासवर्ड को भेजने से पहले base64 कर देते हैं" कोई सिक्योरिटी उपाय नहीं है; वह ट्रांसपोर्ट की सुविधा है। गोपनीयता TLS से आनी चाहिए, वर्णमाला से नहीं।

दूसरी, अपने इनपुट को सीमा दें। base64 स्ट्रिंग का डिकोड साइज़ उसके लंबाई के DecodedLen से ज़्यादा नहीं हो सकता, इसलिए अलोकेट करने से पहले उस आँकड़े की किसी लिमिट के साथ जाँच करें, और रिक्वेस्ट बॉडीज़ को साइज़ सीमा के साथ व्रैप करें, इससे पहले कि कोई डिकोडर उसके हाथ लगे। दोनों चेक एक-एक लाइन के हैं, और मिलकर वे असीमित डिकोड को सीमित डिकोड बना देते हैं।

तीसरी, असावधान इनपुट पर अपनी राय तय करें। Normal मोड आख़िरी ग्रुप के बेकार ट्रेलिंग बिट्स को ख़ामोशी से छोड़ देता है, जिसका मतलब है कि दो अलग-अलग स्ट्रिंग्स एक ही बाइट्स में डिकोड हो सकती हैं। अधिकांश डेटा के लिए यह बात नहीं। पर जो कुछ प्रोटोकॉल का हिस्सा हो, साइन किया हुआ मैसेज हो, या वह मान हो जिसे compared या store किया जाता है, वहाँ Strict() कन्ज़रवेटिव चुनाव है, क्योंकि वह कैनोनिकल फ़ॉर्म को ही एकमात्र स्वीकार फ़ॉर्म बना देता है।

चौथी, सोचें कि डिकोड बाइट्स कहाँ जा रहे हैं। अगर कोई डिकोड मान फ़ाइल-नाम बन जाए, path बन जाए, SQL टुकड़ा बन जाए या कमांड आर्ग्युमेंट बन जाए, तो base64 परत ने आपको किसी चीज़ से नहीं बचाया: बाइट्स अब आपके प्रोग्राम का ग़ैर-भरोसेमंद इनपुट हैं, और सामान्य सैनिटाइज़ेशन नियम बिल्कुल वैसी ही लागू होते हैं जैसे किसी और यूज़र डेटा को लगते।

डिकोडर कितना तेज़ है?

Go में base64 तेज़ है, और बड़े डेटा पर भी तेज़ रहता है, क्योंकि इम्प्लेमेंटेशन एक साधारण टेबल लुकअप लूप है, न रीफ़्लेक्शन के साथ, न चर-दर-चर अलोकेशन के साथ। Go 1.26 चला रहे किसी हाली डेस्कटॉप CPU पर, 500-बाइट की स्ट्रिंग एक अलोकेशन के साथ करीब एक-चौथाई माइक्रोसेकंड में डिकोड होती है, यानी लगभग दो गिगाबाइट प्रति सेकंड के अंदाज़ में। एक मेगाबाइट base64 पूरे एक मिलीसेकंड से कम में डिकोड हो जाती है; एक गिगाबाइट पूरे एक सेकंड से कम में। आँकड़े हार्डवेयर के साथ बदलते हैं, पर शक्ल नहीं: base64 डिकोड ज़्यादातर कभी बॉटलनेक नहीं है; आमतौर पर बॉटलनेक उसके चारों ओर का नेटवर्क या डिस्क होता है।

अगर आप हॉट लूप में हैं, तो अलोकेशन प्रोफ़ाइल ही वह चीज़ है जिसकी नज़र रखें। DecodeString हर कॉल पर नतीजा स्लाइस अलोकेट करता है। Decode पहले-से-साइज़ किया हुआ गंतव्य के साथ और AppendDecode reused बफ़र के साथ दोनों स्थिर स्टेट में उस अलोकेशन को बिल्कुल टाल लेते हैं। ऐसे डिकोड के लिए जो एक रिक्वेस्ट में एक-दो बार होता है, इनमें से कोई बात नहीं; ऐसे डिकोड के लिए जो एक सेकंड में कई मिलियन बार होता है, यह फ्लैट मेमोरी प्रोफ़ाइल और उलझते गार्बेज कलेक्टर के बीच का फ़र्क़ है।

पैकेज का छोटा सा इतिहास

base64 पैकेज Go की स्टैंडर्ड लाइब्रेरी के सबसे पुराने हिस्सों में से एक है। source फ़ाइल के कॉपीराइट हेडर में 2009 लिखा है, वही साल जब भाषा बनी थी, और यह पैकेज पहली ही स्थिर रिलीज़, मार्च 2012 की Go 1.0, से स्टैंडर्ड लाइब्रेरी का हिस्सा है। इसका मतलब है कि DecodeString जो आप आज कॉल करते हैं, वही API है, वही व्यवहार के साथ, जो Go प्रोग्राम एक दशक से ज़्यादा समय से कॉल कर रहे हैं।

उसके बाद की ग्रोथ मध्यम और काम की रही है। अगस्त 2015 की Go 1.5 में बिना-पैडिंग RawStdEncoding और RawURLEncoding values जुड़ीं, जिसने JWT-style कॉम्पैक्ट स्ट्रिंग्स के लिए द्वार खोला। फ़रवरी 2017 की Go 1.8 में Strict() जुड़ा, जिसने प्रोटोकॉल को कैनोनिकल इनपुट माँगने की राह दी। फ़रवरी 2024 की Go 1.22 ने base एन्कोडिंग की पूरी परिवार में AppendDecode और AppendEncode जोड़े, और WithPadding कस दिया गया, जो अब बेवजह आर्ग्युमेंट रिजेक्ट करता है। और सितंबर 2026 तक, नवीनतम रिलीज़ Go 1.27.1 और दूसरी सपोर्टेड लाइन Go 1.26, API बिल्कुल वही है जो इस आर्टिकल में बताया गया है: चार तैयार एन्कोडिंग, एक स्ट्रीम डिकोडर, एक strict मोड, और परफ़ॉर्मेंस के लिए append परिवार।

गहरी बात compatibility promise है। Go 1 की गारंटी का मतलब है कि पैकेज हमेशा वही इनपुट स्वीकार करता रहेगा और वही रिजेक्ट करेगा, इसलिए जो डिकोडर आप इस साल 2015 में बने किसी डेटा फ़ॉर्मेट के लिए लिखते हैं, वह काम करता रहेगा। इतने पुराने और इतने शांत फ़ॉर्मेट के लिए, यही सबसे अच्छी ख़बर है।

वे बातें जो आपको चौंकाएँगी

Go में कुछ समय बिताने के बाद आप base64 से चौंकना बंद कर देते हैं, पर शुरुआती कुछ बारों में इनमें से कुछ बातें ज़ोर से गिरती हैं, इसलिए यहाँ वे हैं:

  • डिकोडर इनपुट में कहीं भी \r और \n स्किप करता है, पर स्पेस नहीं, टैब नहीं, ज़ीरो-विड्थ स्पेस नहीं। यह सहिष्णुता जानबूझकर है; यह MIME-व्रैप इनपुट को काम करने देने के लिए मौजूद है, और spec कब रुकता है, बस वहीं रुकता है।
  • एक फ़ेल डिकोड भी असली डेटा लौटा सकती है। आधा नतीजा बुरी बाइट से पहले का सब कुछ डिकोड किया हुआ है, और एरर उसके साथ आती है, उसके स्थान पर नहीं।
  • CorruptInputError हकीकत में सिर्फ़ एक int64 है जिससे एक मेथड जुड़ी है। "एरर" वही ऑफ़सेट है, और मैसेज माँग पर बनाई जाती है।
  • Decode और Encode दोनों गंतव्य बफ़र का साइज़ देने में आप पर भरोसा करते हैं। उन्हें बहुत छोटा बफ़र दीजिए और एरर नहीं मिलेगी; मिलेगी पैनिक।
  • एक चर चारों बिल्ट-इन एन्कोडिंग में से किसी के लिए भी वैध इनपुट नहीं है। एक base64 चर छह बिट्स उठाता है, और एक बाइट को आठ चाहिए, इसलिए एक चर में पूरा ग्रुप नहीं होता, चाहे पैडिंग वाला हो या नहीं।
  • अगस्त 2026 तक, pkg.go.dev पर 244,000 से ज़्यादा सार्वजनिक पैकेज अपने imports में encoding/base64 को शामिल करते हैं। यह ख़ामोशी से पूरे इकोसिस्टम के उन पैकेज में से एक है जिन पर सबसे ज़्यादा निर्भरता है।

जहाँ डिकोड ख़राब होते हैं

ये वे डिकोडिंग ग़लतियाँ हैं जो बार-बार Go codebases में सामने आती हैं, लगभग उसी क्रम में जिनमें वे सपोर्ट थ्रेड में दिखती हैं:

  • URL-safe डेटा के लिए StdEncoding चुनना (या उल्टा)। लक्षण है पहले -, _, + या / पर एरर, और सुधार है: डिकोडर चुनने से पहले स्ट्रिंग को देख लें।
  • टर्मिनल, ईमेल या PDF से स्ट्रिंग paste करना, जिससे स्पेस, टैब या लाइन-अंत के अवशेष साथ में आ जाते हैं। Go असली न्यूलाइन्स स्किप करता है, पर स्ट्रिंग के बीच की स्पेस ख़राब बाइट है, और एरर का ऑफ़सेट सीधे उसी पर इशारा करेगा।
  • यह भूल जाना कि नतीजा []byte है। उसे raw प्रिंट करने पर आपको नंबर की लिस्ट मिलती है, और उसे ऐसे फ़ंक्शन में डालना जो स्ट्रिंग उम्मीद करता है, string(...) रूपांतरण माँगता है।
  • एरर जाँचना, फिर भी आधा डेटा का इस्तेमाल कर बैठना। आधा-डिकोड प्रिफिक्स असली है, पर वह पेयलॉड नहीं है, और ऐसा कोड जो उसे पेयलॉड मान ले, प्रोडक्शन में फेल होता है - डेटा ठीक-ठीक सही लंबाई की आधी के साथ।
  • Decode बफ़र को len(src) से साइज़ करना, DecodedLen(len(src)) से नहीं। पहला साइज़ उम्मीद की उल्टी दिशा में ग़लत है, और जो पैनिक वह उठाता है वह बड़े इनपुट पर ही होता है, यही वजह है कि यह स्टेजिंग एनवायरनमेंट का पसंदीदा है।
  • समझ लेना कि JWT सेगमेंट में पैडिंग होती है। नहीं होती, और पैडिंग वाला डिकोडर आख़िरी चर पर फेल होता है, ऐसी एरर के साथ जो रहस्य की तरह पढ़ी जाती है। RawURLEncoding इस्तेमाल करें।
  • यह मान लेना कि सारा व्हाइटस्पेस स्किप हो जाता है। नहीं होता। सिर्फ़ दोनों न्यूलाइन चर होते हैं, और क्लिपबोर्ड का "व्हाइटस्पेस" उससे कहीं बड़ा परिवार है।
  • दो-डिकोडिंग करना, या दो बार डिकोड करने में असफल होना, जब मान base64 की base64 हो (वह फ़ाइल जो किसी ईमेल में attach थी, जो खुद किसी और में attach थी)। जाँच एक राउंड ट्रिप है: एक बार डिकोड करें, देखें कि नतीजा अभी भी base64 जैसा लगता है, और तभी दोबारा डिकोड करें।

काम का दूसरा आधा

यह पूरी डिकोडिंग पक्ष की कहानी है: एक पैकेज, चार तैयार डिकोडर, बड़े डेटा के लिए स्ट्रीम डिकोडर, चुनौती देने वाले प्रोटोकॉल के लिए strict मोड, और एरर मैसेज जो वह बाइट बताती हैं जहाँ काम ख़राब हुआ। सहिष्णुता के नियम सीख लें, चरों को देखकर अपना डिकोडर चुनें, अपने इनपुट को सीमा दें, और Go में base64 वह शांत, अनुमान-योग्य, बिना-निर्भरता यूटिलिटी बन जाता है जिसके लिए इसे बनाया गया था।

जब काम पलटता है, और आपका Go प्रोग्राम उन्हें खोलने की जगह base64 स्ट्रिंग्स बनाने की ज़रूरत रखता है, तो Go में Base64 एन्कोडिंग पर संबंधित आर्टिकल उस पक्ष को विस्तार से कवर करता है: एन्कोडर की एक-मेथड API, Close कॉल जो आपके आख़िरी दो बाइट्स को ख़ामोशी से निगल लेता है, MIME के लिए लाइन व्रैपिंग, और चारों एन्कोडिंग उन चैनलों से कैसे map होती हैं जिन पर वे सफ़र करती हैं।

अंतिम अपडेट: 2026-09-08

संबंधित लेख: Go में Base64 एन्कोडिंग: एक सम्पूर्ण गाइड