Giải mã Base64 trong Go — Hướng dẫn encoding/base64

·Systems Engineer·Đánh giá bởiHana Nováková·Đã xuất bản

Sử dụng Giải mã Base64 Trực tuyến miễn phí trực tiếp trên trình duyệt — không cần cài đặt.

Dùng thử Giải mã Base64 Trực tuyến trực tuyến →

Giải mã Base64 trong Go xuất hiện liên tục — kiểm tra JWT, file đính kèm nhị phân, payload API từ các dịch vụ đám mây. Package encoding/base64trong thư viện chuẩn của Go xử lý tất cả điều đó, nhưng chọn sai biến thể bảng mã (chuẩn so với URL-safe, có padding so với không padding) là nguồn gốc phổ biến nhất của lỗi “illegal base64 data”. Hướng dẫn này đề cập đến tất cả biến thể bảng mã, giải mã streaming và bốn lỗi phổ biến. Để giải mã nhanh trên trình duyệt, công cụ Giải mã Base64 của ToolDeck cho kết quả ngay lập tức mà không cần viết một dòng code nào.

  • encoding/base64 là một phần của thư viện chuẩn Go — không cần go get
  • Dùng RawURLEncoding cho JWT token và hầu hết API hiện đại (không padding, bảng chữ cái URL-safe)
  • StdEncoding dùng + và / với padding =; URLEncoding đổi sang - và _ nhưng vẫn giữ padding
  • base64.NewDecoder bọc bất kỳ io.Reader nào để giải mã streaming mà không cần tải vào bộ nhớ
  • Luôn kiểm tra lỗi trả về — padding sai và bảng chữ cái không đúng đều tạo ra lỗi illegal base64 data

Giải mã Base64 là gì?

Mã hóa Base64 biểu diễn dữ liệu nhị phân dưới dạng văn bản ASCII sử dụng 64 ký tự in được (A–Z, a–z, 0–9 và hai ký tự bổ sung). Giải mã thực hiện ngược lại — chuyển đổi biểu diễn ASCII đó trở lại thành các byte gốc. Cứ 4 ký tự Base64 giải mã thành đúng 3 byte. Cơ chế này tồn tại vì nhiều tầng truyền tải (email, HTTP header, trường JSON) được thiết kế cho văn bản, không phải nhị phân thô. Dưới đây là quá trình khứ hồi trông như thế nào:

Go 1.21+
package main

import (
	"encoding/base64"
	"fmt"
)

func main() {
	// Raw bytes → Base64 encoded → decoded back to raw bytes
	original := []byte("service_token:xK9mP2qR")
	// Encoded: "c2VydmljZV90b2tlbjp4SzltUDJxUg=="

	encoded := base64.StdEncoding.EncodeToString(original)
	decoded, _ := base64.StdEncoding.DecodeString(encoded)
	fmt.Println(string(decoded) == string(original)) // true
}

Giải mã Base64 trong Go với encoding/base64

Package encoding/base64 được tích hợp sẵn trong Go — không cần phụ thuộc ngoài. Nó cung cấp bốn biến thể bảng mã được định nghĩa sẵn dưới dạng biến cấp package. Hàm được dùng phổ biến nhất cho đầu vào chuỗi là DecodeString, trả về một byte slice và một error.

Go 1.21+
package main

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

func main() {
	// Base64 chuẩn — bảng chữ cái dùng + và / với padding =
	encoded := "eyJob3N0IjoiZGItcHJvZCF1cy1lYXN0LTEiLCJwb3J0Ijo1NDMyfQ=="
	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}
}

Phương thức Decode hoạt động trên byte slice thay vì chuỗi, và ghi kết quả vào buffer đích được cấp phát trước. Bạn cần định kích thước buffer chính xác — dùng base64.StdEncoding.DecodedLen(len(src)) để lấy kích thước tối đa (có thể lớn hơn độ dài giải mã thực tế vài byte do padding).

Go 1.21+
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}
}
Lưu ý:DecodedLen trả về giới hạn trên, không phải độ dài chính xác. Luôn dùng giá trị trả về n từ Decode để cắt kết quả đúng cách: dst[:n].

StdEncoding và URLEncoding — Chọn biến thể đúng

Đây là nguồn gốc gây nhầm lẫn nhiều nhất. encoding/base64 của Go cung cấp bốn đối tượng bảng mã, và chọn sai một cái chắc chắn sẽ cho bạn lỗi. Sự khác biệt nằm ở hai điểm: bảng chữ cái và padding.

Go 1.21+
package main

import (
	"encoding/base64"
	"fmt"
)

func main() {
	// JWT header payload — URL-safe, không padding
	jwtHeader := "eyJhbGciOiJSUzI1NiIsImtpZCI6IjIwMjMtMDkifQ"

	// Sai: StdEncoding thất bại với đầu vào URL-safe không có padding
	_, err1 := base64.StdEncoding.DecodeString(jwtHeader)
	fmt.Println("StdEncoding error:", err1)
	// StdEncoding error: illegal base64 data at input byte 43

	// Đúng: RawURLEncoding — không padding, bảng chữ cái URL-safe
	decoded, err2 := base64.RawURLEncoding.DecodeString(jwtHeader)
	fmt.Println("RawURLEncoding ok:", err2, "→", string(decoded))
	// RawURLEncoding ok: <nil> → {"alg":"RS256","kid":"2023-09"}
}

Bốn biến thể theo cách diễn đạt đơn giản:

Hàm / Phương thức
Bảng mã
Bắt buộc padding
Trả về
base64.StdEncoding.DecodeString(s)
Chuẩn (+, /)
Có (=)
([]byte, error)
base64.URLEncoding.DecodeString(s)
URL-safe (-, _)
Có (=)
([]byte, error)
base64.RawStdEncoding.DecodeString(s)
Chuẩn (+, /)
Không
([]byte, error)
base64.RawURLEncoding.DecodeString(s)
URL-safe (-, _)
Không
([]byte, error)
base64.StdEncoding.Decode(dst, src)
Chuẩn (+, /)
Có (=)
(n int, error)
base64.NewDecoder(enc, r)
Bất kỳ bảng mã
io.Reader

Quy tắc ngón tay cái của tôi: nếu dữ liệu đến từ JWT, OAuth flow, hoặc SDK của nhà cung cấp đám mây, hãy dùng RawURLEncoding trước. Nếu từ file đính kèm email hoặc form web kiểu cũ, thử StdEncoding. Thông báo lỗi luôn cho bạn biết vị trí byte chính xác nơi giải mã thất bại.

Giải mã Base64 từ File và Phản hồi API

Đọc file được mã hóa Base64

Các file nhị phân (hình ảnh, PDF, chứng chỉ) đôi khi được lưu trữ dưới dạng mã hóa Base64 trên đĩa. Đọc file, loại bỏ khoảng trắng cuối, rồi giải mã:

Go 1.21+
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)
	}

	// Loại bỏ ký tự xuống dòng — file Base64 thường có ngắt dòng mỗi 76 ký tự
	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))
}

Giải mã trường Base64 từ phản hồi JSON của API

Các API đám mây thường trả về dữ liệu nhị phân (khóa mã hóa, blob đã ký, thumbnail) dưới dạng chuỗi Base64 bên trong JSON. Giải nén JSON trước, rồi giải mã trường mục tiêu:

Go 1.21+
package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
)

type SecretResponse struct {
	Name    string `json:"name"`
	Payload string `json:"payload"` // Giá trị bí mật được mã hóa Base64
	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)
}
Lưu ý:Bọc lỗi bằng fmt.Errorf("decode base64: %w", err) thay vì mất ngữ cảnh. Thông báo lỗi gốc từ encoding/base64 bao gồm vị trí byte nơi xảy ra lỗi, rất hữu ích khi debug.

Giải mã Streaming các File Base64 Lớn

Tải file Base64 500 MB vào bộ nhớ bằng os.ReadFile rồi gọi DecodeString sử dụng khoảng 750 MB RAM (chuỗi đã mã hóa cộng với các byte đã giải mã). base64.NewDecoder bọc bất kỳ io.Reader nào và giải mã theo từng chunk, giữ mức sử dụng bộ nhớ gần như không đổi. Kết hợp với io.Copy để tạo pipeline streaming gọn gàng:

Go 1.21+
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)
	}
}
Cảnh báo:base64.NewDecoder yêu cầu dữ liệu Base64 sạch, không bị ngắt quãng. Nếu file nguồn có ngắt dòng (phổ biến trong file PEM và MIME-encoded), hãy bọc reader nguồn bằng một reader loại bỏ dòng hoặc tiền xử lý file để xóa ký tự xuống dòng trước khi streaming.

Giải mã Base64 từ Dòng lệnh

Hầu hết lập trình viên Go thường dùng dòng lệnh trước khi debug. Mọi hệ thống macOS và Linux đều có sẵn lệnh base64; trên Windows, PowerShell có lệnh tương đương tích hợp. Để kiểm tra nhanh API payload, các lệnh này nhanh hơn viết script Go.

bash
# Giải mã chuỗi Base64 (Linux / macOS)
echo "eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9" | base64 --decode
# {"host":"db-prod","port":5432}

# Giải mã và in đẹp với jq (pipe đầu ra JSON)
echo "eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9" | base64 --decode | jq .
# {
#   "host": "db-prod",
#   "port": 5432
# }

# Giải mã file mã hóa Base64 sang nhị phân
base64 --decode < encrypted_payload.b64 > encrypted_payload.bin

# macOS dùng flag -D thay vì --decode
echo "c2VjcmV0LXRva2Vu" | base64 -D

Để kiểm tra JWT token mà không cần cài đặt công cụ nào, dán token vào công cụ Giải mã Base64 của ToolDeck — tách theo dấu chấm và giải mã từng phần.

Giải pháp hiệu năng cao: encoding/base64 đã đủ nhanh

Không giống Python, nơi orjson so với json là cuộc tranh luận hiệu năng có ý nghĩa, encoding/base64 của Go đã được tối ưu hóa bằng assembly và thực sự nhanh cho hầu hết khối lượng công việc. Tuy nhiên, nếu bạn đang xử lý hàng triệu bản ghi trong vòng lặp chặt, filippo.io/base64 cung cấp giải mã tăng tốc SIMD với API tương thích trực tiếp.

bash
go get filippo.io/base64
Go 1.21+
package main

import (
	"fmt"
	"log"

	"filippo.io/base64"
)

func main() {
	// Thay thế trực tiếp — cùng API với 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}
}

Lợi ích hiệu năng rõ ràng nhất trên amd64 với hỗ trợ AVX2 — benchmark cho thấy cải thiện thông lượng 2–4x trên đầu vào lớn. Để giải mã phản hồi API hằng ngày (vài trăm byte mỗi lần), hãy dùng thư viện chuẩn.

Giải mã Payload JWT Base64 trong Go

Kiểm tra JWT xuất hiện trong hầu hết mọi dịch vụ backend. Theo kinh nghiệm của tôi, hầu hết phiên debug đều quy về câu hỏi “token này thực sự chứa gì?” — và bạn có thể trả lời mà không cần đưa vào thư viện JWT đầy đủ. Token có ba đoạn mã hóa Base64url được phân tách bởi dấu chấm. Đoạn giữa là payload mà bạn thực sự cần:

Go 1.21+
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 dùng RawURLEncoding — bảng chữ cái URL-safe, không padding =
	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]
}

Lỗi Thường Gặp

Tôi đã gặp cả bốn lỗi này trong các code review thực tế — hai lỗi đầu đặc biệt xuất hiện hầu như mỗi lần ai đó tích hợp auth provider mới.

Dùng StdEncoding với đầu vào URL-safe

Vấn đề: JWT token và OAuth token dùng bảng chữ cái Base64 URL-safe (- và _). Truyền chúng vào StdEncoding.DecodeString sẽ thất bại với lỗi 'illegal base64 data'.

Giải pháp: Kiểm tra nguồn đầu vào: token từ hệ thống auth dùng RawURLEncoding; file đính kèm nhị phân dùng StdEncoding.

Before · Go
After · Go
// JWT header — URL-safe, không padding
token := "eyJhbGciOiJSUzI1NiJ9"
decoded, err := base64.StdEncoding.DecodeString(token)
// err: illegal base64 data at input byte 19
// JWT header — bảng mã đúng
token := "eyJhbGciOiJSUzI1NiJ9"
decoded, err := base64.RawURLEncoding.DecodeString(token)
// decoded: {"alg":"RS256"}
// err: nil
Bỏ qua giá trị trả về n từ Decode

Vấn đề: Decode ghi vào buffer được cấp phát trước và trả về số byte thực sự được ghi. DecodedLen trả về giới hạn trên, nên phần cuối buffer có thể chứa byte rác.

Giải pháp: Luôn cắt kết quả với dst[:n] — không phải dst[:len(dst)].

Before · Go
After · Go
dst := make([]byte, base64.StdEncoding.DecodedLen(len(src)))
base64.StdEncoding.Decode(dst, src)
fmt.Println(string(dst)) // có thể bao gồm byte zero ở cuối
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])) // đúng — chỉ các byte đã giải mã
Không loại bỏ khoảng trắng trước khi giải mã

Vấn đề: Chuỗi Base64 được sao chép từ terminal, email, hoặc config file thường có ký tự xuống dòng hoặc khoảng trắng ở cuối. Truyền trực tiếp vào DecodeString sẽ thất bại tại ký tự khoảng trắng.

Giải pháp: Gọi strings.TrimSpace (và strings.ReplaceAll với ký tự xuống dòng nhúng) trước khi giải mã.

Before · Go
After · Go
// Giá trị đọc từ config file có ký tự xuống dòng ở cuối
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
Lưu trữ byte đã giải mã dưới dạng chuỗi không đúng cách

Vấn đề: Gọi string(decoded) trên dữ liệu nhị phân (hình ảnh, payload nén) tạo ra chuỗi UTF-8 không hợp lệ. Chuỗi Go có thể giữ byte tùy ý, nhưng một số thao tác sẽ làm hỏng nội dung.

Giải pháp: Giữ dữ liệu nhị phân dưới dạng []byte trong toàn bộ pipeline. Chỉ gọi string(decoded) khi nội dung giải mã được đảm bảo là văn bản.

Before · Go
After · Go
decoded, _ := base64.StdEncoding.DecodeString(pngBase64)
// Xử lý PNG nhị phân như chuỗi sẽ mất dữ liệu
imageStr := string(decoded)
os.WriteFile("image.png", []byte(imageStr), 0644) // có thể bị hỏng
decoded, err := base64.StdEncoding.DecodeString(pngBase64)
if err != nil {
    log.Fatal(err)
}
// Ghi byte trực tiếp — không chuyển đổi sang chuỗi
os.WriteFile("image.png", decoded, 0644)

So sánh các Phương thức

Tất cả các biến thể đều có trong thư viện chuẩn — không cần phụ thuộc ngoài cho bất kỳ phương thức nào trong số này.

Phương thức
Kiểu đầu vào
Biến thể bảng mã
Streaming
Bảng chữ cái tùy chỉnh
Padding tùy chỉnh
Cần cài đặt
StdEncoding.DecodeString
string
Chuẩn
Không (stdlib)
URLEncoding.DecodeString
string
URL-safe
Không (stdlib)
RawStdEncoding.DecodeString
string
Chuẩn (không pad)
Không (stdlib)
RawURLEncoding.DecodeString
string
URL-safe (không pad)
Không (stdlib)
StdEncoding.Decode
[]byte
Chuẩn
Không (stdlib)
base64.NewDecoder
io.Reader
Bất kỳ
Không (stdlib)
encoding/base64 + NewEncoding
string
Bảng chữ cái tùy chỉnh
Không (stdlib)

Cho JWT token và OAuth flow: RawURLEncoding. Cho file đính kèm email và dữ liệu MIME: StdEncoding. Cho file nhị phân lớn từ đĩa hoặc mạng: bọc reader trong base64.NewDecoder — giữ mức sử dụng bộ nhớ không đổi bất kể kích thước file. Cần bảng chữ cái tùy chỉnh? base64.NewEncoding(alphabet) tạo đối tượng bảng mã mới cho các trường hợp đặc biệt.

Để kiểm tra nhanh trong quá trình phát triển, công cụ Giải mã Base64 trực tuyến nhanh hơn khởi động một chương trình Go.

Câu hỏi Thường gặp

Làm thế nào để giải mã chuỗi Base64 trong Go?

Import encoding/base64 và gọi base64.StdEncoding.DecodeString(s). Hàm này trả về ([]byte, error) — luôn kiểm tra lỗi. Nếu chuỗi sử dụng ký tự URL-safe (- và _ thay vì + và /), dùng base64.URLEncoding.DecodeString. Với JWT token và hầu hết các API hiện đại, RawURLEncoding (không có padding) là lựa chọn đúng đắn.

Go 1.21+
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"}
}

Sự khác biệt giữa StdEncoding và URLEncoding trong Go là gì?

StdEncoding sử dụng bảng chữ cái Base64 chuẩn với ký tự + và / cùng padding = — được định nghĩa trong RFC 4648 §4. URLEncoding thay + bằng - và / bằng _ để đầu ra an toàn trong URL và HTTP header mà không cần percent-encoding — được định nghĩa trong RFC 4648 §5. Dùng URLEncoding cho JWT token, OAuth token, và dữ liệu nhúng trong query string.

Go 1.21+
package main

import (
	"encoding/base64"
	"fmt"
)

func main() {
	// Standard: có thể chứa ký tự + / và =
	std := base64.StdEncoding.EncodeToString([]byte("hello/world"))
	fmt.Println(std) // "aGVsbG8vd29ybGQ="

	// URL-safe: thay + bằng - và / bằng _
	url := base64.URLEncoding.EncodeToString([]byte("hello/world"))
	fmt.Println(url) // "aGVsbG8vd29ybGQ=" (giống nhau — khác thể hiện khi byte khác nhau)

	// JWT header không bao giờ có padding — dùng RawURLEncoding
	raw := base64.RawURLEncoding.EncodeToString([]byte("hello/world"))
	fmt.Println(raw) // "aGVsbG8vd29ybGQ" (không có = cuối)
}

Làm thế nào để sửa lỗi "illegal base64 data" trong Go?

Lỗi này có nghĩa là đầu vào chứa ký tự ngoài bảng chữ cái mong đợi, hoặc padding sai. Ba nguyên nhân phổ biến: dùng StdEncoding trên đầu vào URL-safe (đổi sang URLEncoding), dùng encoder có padding trên đầu vào không có padding (đổi sang RawStdEncoding/RawURLEncoding), hoặc có khoảng trắng/ký tự xuống dòng ở cuối. Dùng strings.TrimSpace để loại bỏ khoảng trắng trước khi giải mã.

Go 1.21+
package main

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

func main() {
	// Đầu vào từ webhook payload — có ký tự xuống dòng bị loại bỏ khỏi wire format
	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
}

Làm thế nào để giải mã streaming một file Base64 lớn trong Go?

Dùng base64.NewDecoder(base64.StdEncoding, reader) để bọc bất kỳ io.Reader nào và giải mã ngay khi đọc. Kết hợp với io.Copy để ghi vào đích mà không cần đưa toàn bộ file vào bộ nhớ. Đây là pattern chuẩn để giải mã các file đính kèm nhị phân hoặc payload dữ liệu lớn được mã hóa Base64.

Go 1.21+
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)
}

Có thể giải mã payload Base64 JWT trong Go mà không cần thư viện JWT không?

Có. JWT là ba đoạn được mã hóa Base64url nối với nhau bằng dấu chấm. Tách theo "." và giải mã đoạn thứ hai (index 1) bằng base64.RawURLEncoding.DecodeString — JWT header và payload dùng bảng chữ cái URL-safe và không có padding. Đoạn chữ ký (index 2) là nhị phân và thường chỉ cần khi xác minh.

Go 1.21+
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"}
}

Nên dùng bảng mã nào để giải mã dữ liệu Base64 từ phản hồi HTTP API?

Kiểm tra tài liệu API hoặc quan sát chuỗi được mã hóa. Nếu chứa ký tự + hoặc / và kết thúc bằng =, dùng StdEncoding. Nếu dùng ký tự - và _ không có =, dùng RawURLEncoding. Khi không chắc, thử RawURLEncoding trước — hầu hết các API hiện đại (OAuth2, JWT, Google Cloud, AWS) dùng Base64 URL-safe không có padding.

Go 1.21+
package main

import (
	"encoding/base64"
	"strings"
)

// Phát hiện biến thể bảng mã từ chuỗi được mã hóa
func decodeAPIPayload(encoded string) ([]byte, error) {
	// Ký tự URL-safe không có padding — phổ biến trong các API hiện đại
	if !strings.Contains(encoded, "+") && !strings.Contains(encoded, "/") {
		return base64.RawURLEncoding.DecodeString(encoded)
	}
	// Base64 chuẩn có padding
	return base64.StdEncoding.DecodeString(encoded)
}

Công cụ Liên quan

  • Mã hóa Base64 — mã hóa dữ liệu nhị phân hoặc văn bản sang Base64 trên trình duyệt, hữu ích để tạo test fixture dán vào unit test Go của bạn.
  • Giải mã JWT — tách và giải mã cả ba đoạn JWT cùng lúc, với kiểm tra payload theo từng trường — không cần code Go khi bạn chỉ cần đọc token trong quá trình debug.
  • Giải mã URL — giải mã percent-encode các chuỗi URL-encoded, tiện lợi khi phản hồi API kết hợp dữ liệu Base64url với các query parameter được percent-encode.
  • Định dạng JSON — sau khi giải mã payload JWT Base64 hoặc phản hồi API, dán JSON vào đây để in đẹp và xác thực cấu trúc ngay lập tức.
Cũng có sẵn trong:JavaScriptPythonJavaC#
JO
James OkaforSystems Engineer

James is a systems engineer and Go enthusiast who focuses on high-performance microservices, command-line tooling, and infrastructure automation. He enjoys the simplicity and explicitness of Go and writes about building fast, reliable backend systems. When not coding he explores distributed systems concepts and contributes to open-source Go libraries.

HN
Hana NovákováNgười đánh giá kỹ thuật

Hana is a backend engineer who has built production gRPC and REST services in Go for cloud-native environments. She cares deeply about API correctness, protobuf schema design, and the operational side of running Go services in Kubernetes. She writes about the Go standard library, encoding and marshalling patterns, gRPC best practices, and the subtleties of writing idiomatic Go that is easy to test and maintain.