Dekódování Base64 v Go se objevuje neustále — při inspekci JWT, binárních přílohách souborů a API payloadech cloudových služeb. Standardní balíček encoding/base64v Go zvládne vše, ale výběr špatné varianty kódování (standardní vs. URL-safe, s paddingem vs. bez paddingu) je nejčastější příčinou chyb “illegal base64 data”. Tato příručka pokrývá StdEncoding, URLEncoding, RawURLEncoding, streamované dekódování pomocí base64.NewDecoder, inspekci JWT payloadů a čtyři chyby, na které narazí téměř každý poprvé. Pro jednorázové dekódování v prohlížeči Base64 Decoder od ToolDeck vyřeší úkol okamžitě bez napsání jediného řádku kódu.
- ✓encoding/base64 je součástí standardní knihovny Go — není potřeba go get
- ✓Pro JWT tokeny a většinu moderních API použijte RawURLEncoding (bez paddingu, URL-safe abeceda)
- ✓StdEncoding používá + a / s paddingem =; URLEncoding přechází na - a _, ale padding zachovává
- ✓base64.NewDecoder obalí libovolný io.Reader pro streamované dekódování bez načtení do paměti
- ✓Vždy kontrolujte vrácenou chybu — neplatný padding a špatná abeceda způsobují illegal base64 data
Co je dekódování Base64?
Base64 kódování reprezentuje binární data jako ASCII text pomocí 64 tisknutelných znaků (A–Z, a–z, 0–9 a dva doplňkové znaky). Dekódování tento proces obrací — převádí tuto ASCII reprezentaci zpět na původní bajty. Každé 4 znaky Base64 dekódují přesně 3 bajty. Schéma existuje proto, že mnoho přenosových vrstev (e-mail, HTTP hlavičky, JSON pole) je navrženo pro text, nikoliv pro surová binární data. Takto vypadá kompletní cyklus:
package main
import (
"encoding/base64"
"fmt"
)
func main() {
// Surové bajty → Base64 kódování → dekódování zpět na surové bajty
original := []byte("service_token:xK9mP2qR")
// Zakódováno: "c2VydmljZV90b2tlbjp4SzltUDJxUg=="
encoded := base64.StdEncoding.EncodeToString(original)
decoded, _ := base64.StdEncoding.DecodeString(encoded)
fmt.Println(string(decoded) == string(original)) // true
}Dekódování Base64 v Go pomocí encoding/base64
Balíček encoding/base64 se dodává s Go — bez externích závislostí. Nabízí čtyři předdefinované varianty kódování jako proměnné na úrovni balíčku. Nejpoužívanější funkcí pro řetězcový vstup je DecodeString, která vrací byte slice a chybu.
package main
import (
"encoding/base64"
"fmt"
"log"
)
func main() {
// Standardní Base64 — abeceda používá + a / s paddingem =
encoded := "eyJob3N0IjoiZGItcHJvZC51cy1lYXN0LTEiLCJwb3J0Ijo1NDMyfQ=="
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
log.Fatalf("decode error: %v", err)
}
fmt.Println(string(decoded))
// {"host":"db-prod.us-east-1","port":5432}
}Metoda Decode pracuje s byte slicy místo řetězců a zapisuje výsledek do předem alokovaného cílového bufferu. Buffer musíte správně dimenzovat — použijte base64.StdEncoding.DecodedLen(len(src)) pro získání maximální velikosti (může být o několik bajtů větší než skutečná dekódovaná délka kvůli paddingu).
package main
import (
"encoding/base64"
"fmt"
"log"
)
func main() {
src := []byte("eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9")
dst := make([]byte, base64.RawStdEncoding.DecodedLen(len(src)))
n, err := base64.RawStdEncoding.Decode(dst, src)
if err != nil {
log.Fatalf("decode: %v", err)
}
fmt.Println(string(dst[:n]))
// {"host":"db-prod","port":5432}
}DecodedLen vrací horní mez, nikoliv přesnou délku. Vždy použijte návratovou hodnotu n z Decode pro správné oříznutí výsledku: dst[:n].StdEncoding vs URLEncoding — výběr správné varianty
Zde vzniká většina zmatku. Balíček encoding/base64 v Go nabízí čtyři objekty kódování a výběr špatného zaručeně způsobí chybu. Rozdíl spočívá ve dvou věcech: abecedě a paddingu.
package main
import (
"encoding/base64"
"fmt"
)
func main() {
// JWT header payload — URL-safe, bez paddingu
jwtHeader := "eyJhbGciOiJSUzI1NiIsImtpZCI6IjIwMjMtMDkifQ"
// Špatně: StdEncoding selže na URL-safe vstupu bez paddingu
_, err1 := base64.StdEncoding.DecodeString(jwtHeader)
fmt.Println("StdEncoding error:", err1)
// StdEncoding error: illegal base64 data at input byte 43
// Správně: RawURLEncoding — bez paddingu, URL-safe abeceda
decoded, err2 := base64.RawURLEncoding.DecodeString(jwtHeader)
fmt.Println("RawURLEncoding ok:", err2, "→", string(decoded))
// RawURLEncoding ok: <nil> → {"alg":"RS256","kid":"2023-09"}
}Čtyři varianty srozumitelně:
Moje praktické pravidlo: pokud data pocházejí z JWT, OAuth flow nebo SDK cloudového poskytovatele, sáhněte nejprve po RawURLEncoding. Pokud pocházejí z e-mailových příloh nebo starých webových formulářů, zkuste StdEncoding. Chybová zpráva vždy uvádí přesnou pozici bajtu, kde dekódování selhalo.
Dekódování Base64 ze souboru a odpovědi API
Čtení Base64-kódovaného souboru
Binární soubory (obrázky, PDF, certifikáty) jsou někdy uloženy Base64-kódované na disku. Přečtěte soubor, odstraňte případné bílé znaky na konci a pak dekódujte:
package main
import (
"encoding/base64"
"fmt"
"log"
"os"
"strings"
)
func main() {
raw, err := os.ReadFile("certificate.pem.b64")
if err != nil {
log.Fatalf("read file: %v", err)
}
// Odstraňte odřádkování — Base64 soubory mají často zalomení každých 76 znaků
cleaned := strings.ReplaceAll(strings.TrimSpace(string(raw)), "\n", "")
decoded, err := base64.StdEncoding.DecodeString(cleaned)
if err != nil {
log.Fatalf("decode: %v", err)
}
if err := os.WriteFile("certificate.pem", decoded, 0600); err != nil {
log.Fatalf("write: %v", err)
}
fmt.Printf("decoded %d bytes → certificate.pem\n", len(decoded))
}Dekódování Base64 pole z JSON odpovědi API
Cloudová API často vrací binární data (šifrovací klíče, podepsané bloby, náhledy) jako Base64 řetězce uvnitř JSON. Nejprve rozparsujte JSON, pak dekódujte cílové pole:
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net/http"
)
type SecretResponse struct {
Name string `json:"name"`
Payload string `json:"payload"` // Base64-kódovaná hodnota tajemství
Version int `json:"version"`
}
func fetchAndDecodeSecret(secretURL string) ([]byte, error) {
resp, err := http.Get(secretURL)
if err != nil {
return nil, fmt.Errorf("http get: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status: %d", resp.StatusCode)
}
var secret SecretResponse
if err := json.NewDecoder(resp.Body).Decode(&secret); err != nil {
return nil, fmt.Errorf("decode json: %w", err)
}
value, err := base64.StdEncoding.DecodeString(secret.Payload)
if err != nil {
return nil, fmt.Errorf("decode base64: %w", err)
}
return value, nil
}
func main() {
value, err := fetchAndDecodeSecret("https://api.example.com/secrets/db-password")
if err != nil {
log.Fatalf("fetch secret: %v", err)
}
fmt.Printf("secret value: %s\n", value)
}fmt.Errorf("decode base64: %w", err) místo ztráty kontextu. Původní chybová zpráva z encoding/base64 obsahuje pozici bajtu selhání, což je užitečné při ladění.Streamové zpracování velkých Base64-kódovaných souborů
Načtení 500 MB Base64-kódovaného souboru do paměti pomocí os.ReadFile a následné volání DecodeString spotřebuje zhruba 750 MB RAM (kódovaný řetězec plus dekódované bajty). base64.NewDecoder obalí libovolný io.Reader a dekóduje po částech, přičemž spotřeba paměti zůstává téměř konstantní. Kombinujte ho s io.Copy pro čisté streamové zpracování:
package main
import (
"encoding/base64"
"fmt"
"io"
"log"
"os"
)
func streamDecodeFile(srcPath, dstPath string) error {
src, err := os.Open(srcPath)
if err != nil {
return fmt.Errorf("open source: %w", err)
}
defer src.Close()
dst, err := os.Create(dstPath)
if err != nil {
return fmt.Errorf("create dest: %w", err)
}
defer dst.Close()
decoder := base64.NewDecoder(base64.StdEncoding, src)
written, err := io.Copy(dst, decoder)
if err != nil {
return fmt.Errorf("stream decode: %w", err)
}
fmt.Printf("written %d bytes to %s\n", written, dstPath)
return nil
}
func main() {
if err := streamDecodeFile("backup.tar.b64", "backup.tar"); err != nil {
log.Fatal(err)
}
}base64.NewDecoder očekává čistá, nepřerušená Base64 data. Pokud zdrojový soubor obsahuje zalomení řádků (běžné u PEM a MIME-kódovaných souborů), obalte zdrojový reader čtečkou odstraňující řádky nebo soubor předem zpracujte a odřádkování odstraňte před streamováním.Dekódování Base64 z příkazové řádky
Většina Go vývojářů sahá nejprve po příkazové řádce při ladění. Každý systém macOS a Linux obsahuje příkaz base64; na Windows má PowerShell zabudovaný ekvivalent. Pro rychlou inspekci API payloadů je to rychlejší než psát Go skript.
# Dekódování Base64 řetězce (Linux / macOS)
echo "eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9" | base64 --decode
# {"host":"db-prod","port":5432}
# Dekódování a formátování pomocí jq (přesměrování JSON výstupu)
echo "eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9" | base64 --decode | jq .
# {
# "host": "db-prod",
# "port": 5432
# }
# Dekódování Base64-kódovaného souboru do binárního formátu
base64 --decode < encrypted_payload.b64 > encrypted_payload.bin
# macOS používá přepínač -D místo --decode
echo "c2VjcmV0LXRva2Vu" | base64 -DPro inspekci JWT tokenů bez nainstalovaných nástrojů vložte token do Base64 Decoderu od ToolDeck — rozdělte na tečky a dekódujte každou část.
Výkonná alternativa: encoding/base64 je již rychlý
Na rozdíl od Pythonu, kde je diskuse o výkonu orjson vs. json smysluplná, je encoding/base64 v Go již optimalizovaný pomocí assembleru a skutečně rychlý pro většinu pracovních zátěží. Pokud ale zpracováváte miliony záznamů v těsné smyčce, filippo.io/base64 poskytuje SIMD-akcelerované dekódování s kompatibilním API.
go get filippo.io/base64
package main
import (
"fmt"
"log"
"filippo.io/base64"
)
func main() {
// Drop-in náhrada — stejné API jako encoding/base64
encoded := "eyJob3N0IjoiY2FjaGUtcHJvZCIsInBvcnQiOjYzNzl9"
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
log.Fatalf("decode: %v", err)
}
fmt.Println(string(decoded))
// {"host":"cache-prod","port":6379}
}Výkonnostní přínos je nejviditelnější na amd64 s podporou AVX2 — benchmarky ukazují 2–4x zlepšení propustnosti pro velké vstupy. Pro každodenní dekódování API odpovědí (několik set bajtů najednou) zůstaňte u standardní knihovny.
Dekódování Base64 JWT payload v Go
Inspekce JWT se vyskytuje téměř v každé backendové službě. Podle mých zkušeností se většina ladících relací scvrkne na otázku “co je vlastně v tomto tokenu?” — a na to dokážete odpovědět bez načítání kompletní JWT knihovny. Token má tři Base64url-kódované segmenty oddělené tečkami. Prostřední segment je payload, který vás skutečně zajímá:
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"log"
"strings"
)
type JWTPayload struct {
Subject string `json:"sub"`
Issuer string `json:"iss"`
Expiry int64 `json:"exp"`
Roles []string `json:"roles"`
}
func decodeJWTPayload(token string) (*JWTPayload, error) {
parts := strings.Split(token, ".")
if len(parts) != 3 {
return nil, fmt.Errorf("invalid JWT: expected 3 segments, got %d", len(parts))
}
// JWT používá RawURLEncoding — URL-safe abeceda, bez paddingu =
raw, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
return nil, fmt.Errorf("decode payload: %w", err)
}
var payload JWTPayload
if err := json.Unmarshal(raw, &payload); err != nil {
return nil, fmt.Errorf("unmarshal payload: %w", err)
}
return &payload, nil
}
func main() {
token := "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c3ItNDQyIiwiaXNzIjoiYXV0aC5leGFtcGxlLmNvbSIsImV4cCI6MTc0MTk1NjgwMCwicm9sZXMiOlsiYWRtaW4iLCJhdWRpdG9yIl19.SIGNATURE"
payload, err := decodeJWTPayload(token)
if err != nil {
log.Fatalf("jwt: %v", err)
}
fmt.Printf("Subject: %s\n", payload.Subject)
fmt.Printf("Issuer: %s\n", payload.Issuer)
fmt.Printf("Roles: %v\n", payload.Roles)
// Subject: usr-442
// Issuer: auth.example.com
// Roles: [admin auditor]
}Časté chyby
Všechny čtyři jsem narazil v reálných code review — první dvě se objevují téměř pokaždé, když někdo integruje nového poskytovatele autentizace.
Problém: JWT tokeny a OAuth tokeny používají URL-safe Base64 abecedu (- a _). Jejich předání do StdEncoding.DecodeString selže s chybou 'illegal base64 data'.
Řešení: Zkontrolujte zdroj vstupu: tokeny z autentizačních systémů používají RawURLEncoding; binární přílohy používají StdEncoding.
// JWT hlavička — URL-safe, bez paddingu token := "eyJhbGciOiJSUzI1NiJ9" decoded, err := base64.StdEncoding.DecodeString(token) // err: illegal base64 data at input byte 19
// JWT hlavička — správné kódování
token := "eyJhbGciOiJSUzI1NiJ9"
decoded, err := base64.RawURLEncoding.DecodeString(token)
// decoded: {"alg":"RS256"}
// err: nilProblém: Decode zapisuje do předem alokovaného bufferu a vrací počet skutečně zapsaných bajtů. DecodedLen vrací horní mez, takže konec bufferu může obsahovat odpadní bajty.
Řešení: Vždy ořízněte výsledek pomocí dst[:n] — nikoliv dst[:len(dst)].
dst := make([]byte, base64.StdEncoding.DecodedLen(len(src))) base64.StdEncoding.Decode(dst, src) fmt.Println(string(dst)) // může obsahovat koncové nulové bajty
dst := make([]byte, base64.StdEncoding.DecodedLen(len(src)))
n, err := base64.StdEncoding.Decode(dst, src)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(dst[:n])) // správně — pouze dekódované bajtyProblém: Base64 řetězce zkopírované z terminálů, e-mailů nebo konfiguračních souborů mají často koncové odřádkování nebo mezery. Jejich přímé předání do DecodeString selže na bílém znaku.
Řešení: Zavolejte strings.TrimSpace (a strings.ReplaceAll pro vložená odřádkování) před dekódováním.
// Hodnota načtená z konfiguračního souboru s koncovým odřádkováním encoded := "c2VydmljZV9rZXk6eEtNcDI=\n" decoded, err := base64.StdEncoding.DecodeString(encoded) // err: illegal base64 data at input byte 24
encoded := "c2VydmljZV9rZXk6eEtNcDI=\n" cleaned := strings.TrimSpace(encoded) decoded, err := base64.StdEncoding.DecodeString(cleaned) // decoded: "service_key:xKMp2" // err: nil
Problém: Volání string(decoded) na binárních datech (obrázky, komprimované payloady) vytváří neplatné UTF-8 řetězce. Go řetězce mohou držet libovolné bajty, ale některé operace obsah poničí.
Řešení: Uchovávejte binární data jako []byte po celou dobu zpracování. Volání string(decoded) používejte pouze tehdy, když je dekódovaný obsah zaručeně text.
decoded, _ := base64.StdEncoding.DecodeString(pngBase64)
// Zpracování binárního PNG jako řetězce způsobí ztrátu dat
imageStr := string(decoded)
os.WriteFile("image.png", []byte(imageStr), 0644) // může poškodit soubordecoded, err := base64.StdEncoding.DecodeString(pngBase64)
if err != nil {
log.Fatal(err)
}
// Zapište bajty přímo — bez převodu na řetězec
os.WriteFile("image.png", decoded, 0644)Porovnání metod
Všechny varianty jsou součástí standardní knihovny — žádná z nich nevyžaduje externí závislosti.
Pro JWT tokeny a OAuth flow: RawURLEncoding. Pro e-mailové přílohy a MIME data: StdEncoding. Pro velké binární soubory z disku nebo sítě: obalte reader do base64.NewDecoder — spotřeba paměti zůstane konstantní bez ohledu na velikost souboru. Potřebujete vlastní abecedu? base64.NewEncoding(alphabet) vytvoří nový objekt kódování pro specifické případy užití.
Pro rychlé jednorázové kontroly při vývoji je online Base64 decoder rychlejší než spouštět Go program.
Často kladené otázky
Jak dekóduji Base64 řetězec v Go?
Importujte encoding/base64 a zavolejte base64.StdEncoding.DecodeString(s). Vrací ([]byte, error) — vždy zkontrolujte chybu. Pokud řetězec používá URL-safe znaky (- a _ místo + a /), použijte base64.URLEncoding.DecodeString. Pro JWT tokeny a většinu moderních API je správnou volbou RawURLEncoding (bez paddingu).
package main
import (
"encoding/base64"
"fmt"
"log"
)
func main() {
encoded := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
decoded, err := base64.RawURLEncoding.DecodeString(encoded)
if err != nil {
log.Fatalf("decode: %v", err)
}
fmt.Println(string(decoded))
// {"alg":"HS256","typ":"JWT"}
}Jaký je rozdíl mezi StdEncoding a URLEncoding v Go?
StdEncoding používá standardní Base64 abecedu se znaky + a / a padding = — definováno v RFC 4648 §4. URLEncoding nahrazuje + za - a / za _, čímž je výstup bezpečný v URL a HTTP hlavičkách bez percent-kódování — definováno v RFC 4648 §5. Používejte URLEncoding pro JWT tokeny, OAuth tokeny a data vložená do query řetězců.
package main
import (
"encoding/base64"
"fmt"
)
func main() {
// Standardní: může obsahovat znaky + / a =
std := base64.StdEncoding.EncodeToString([]byte("hello/world"))
fmt.Println(std) // "aGVsbG8vd29ybGQ="
// URL-safe: nahrazuje + za - a / za _
url := base64.URLEncoding.EncodeToString([]byte("hello/world"))
fmt.Println(url) // "aGVsbG8vd29ybGQ=" (stejné — rozdíl se projeví u jiných bajtů)
// JWT hlavičky nikdy nemají padding — použijte RawURLEncoding
raw := base64.RawURLEncoding.EncodeToString([]byte("hello/world"))
fmt.Println(raw) // "aGVsbG8vd29ybGQ" (bez koncového =)
}Jak opravím chybu "illegal base64 data" v Go?
Tato chyba znamená, že vstup obsahuje znaky mimo očekávanou abecedu nebo je chybný padding. Tři nejčastější příčiny: použití StdEncoding na URL-safe vstup (přepněte na URLEncoding), použití kodéru s paddingem na vstup bez paddingu (přepněte na RawStdEncoding/RawURLEncoding), nebo bílé znaky či odřádkování na konci. Před dekódováním odstraňte bílé znaky pomocí strings.TrimSpace.
package main
import (
"encoding/base64"
"fmt"
"log"
"strings"
)
func main() {
// Vstup z webhooku — má odstraněné odřádkování z přenosového formátu
raw := " aGVsbG8gd29ybGQ= \n"
cleaned := strings.TrimSpace(raw)
decoded, err := base64.StdEncoding.DecodeString(cleaned)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(decoded)) // hello world
}Jak streamovat dekódování velkého Base64-kódovaného souboru v Go?
Použijte base64.NewDecoder(base64.StdEncoding, reader), který obalí libovolný io.Reader a dekóduje za chodu. Napojte ho přes io.Copy pro zápis do cíle bez bufferování celého souboru v paměti. Toto je standardní vzor pro dekódování Base64-kódovaných binárních příloh nebo velkých datových payloadů.
package main
import (
"encoding/base64"
"io"
"log"
"os"
)
func main() {
src, err := os.Open("attachment.b64")
if err != nil {
log.Fatal(err)
}
defer src.Close()
dst, err := os.Create("attachment.bin")
if err != nil {
log.Fatal(err)
}
defer dst.Close()
decoder := base64.NewDecoder(base64.StdEncoding, src)
io.Copy(dst, decoder)
}Mohu dekódovat Base64 JWT payload v Go bez JWT knihovny?
Ano. JWT jsou tři Base64url-kódované segmenty oddělené tečkami. Rozdělte na "." a dekódujte druhý segment (index 1) pomocí base64.RawURLEncoding.DecodeString — JWT hlavičky a payloady používají URL-safe abecedu bez paddingu. Segment podpisu (index 2) je binární a obvykle je potřeba pouze pro ověření.
package main
import (
"encoding/base64"
"fmt"
"log"
"strings"
)
func main() {
token := "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c3ItOTAxIiwicm9sZSI6ImFkbWluIn0.SIG"
parts := strings.Split(token, ".")
if len(parts) < 2 {
log.Fatal("invalid JWT format")
}
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
log.Fatalf("decode payload: %v", err)
}
fmt.Println(string(payload))
// {"sub":"usr-901","role":"admin"}
}Jaké kódování použít pro dekódování Base64 dat z odpovědi HTTP API?
Zkontrolujte dokumentaci API nebo prozkoumejte kódovaný řetězec. Pokud obsahuje znaky + nebo / a končí na =, použijte StdEncoding. Pokud používá znaky - a _ bez =, použijte RawURLEncoding. Při nejistotě zkuste nejprve RawURLEncoding — většina moderních API (OAuth2, JWT, Google Cloud, AWS) používá URL-safe Base64 bez paddingu.
package main
import (
"encoding/base64"
"strings"
)
// Detekce varianty kódování z kódovaného řetězce
func decodeAPIPayload(encoded string) ([]byte, error) {
// URL-safe znaky bez paddingu — běžné v moderních API
if !strings.Contains(encoded, "+") && !strings.Contains(encoded, "/") {
return base64.RawURLEncoding.DecodeString(encoded)
}
// Standardní Base64 s paddingem
return base64.StdEncoding.DecodeString(encoded)
}Související nástroje
- Base64 Encoder — zakódujte binární data nebo text do Base64 v prohlížeči, vhodné pro generování testovacích fixture dat ke vložení do Go unit testů.
- JWT Decoder — rozdělte a dekódujte všechny tři JWT segmenty najednou s inspekcí payloadu pole po poli — žádný Go kód není potřeba, když jen potřebujete přečíst token při ladění.
- URL Decoder — percent-dekódujte URL-kódované řetězce, praktické když API odpovědi kombinují Base64url data s percent-kódovanými query parametry.
- JSON Formatter — po dekódování Base64 JWT payloadu nebo API odpovědi vložte JSON sem pro okamžité formátování a validaci struktury.