Base64是一种用64个可打印字符来表示二进制数据的方法。叫64是因为用了64个字符。
一、需求
计算机底层是二进制(0和1),但很多传输通道只支持文本。比如:
- 电子邮件:早期SMTP协议只支持ASCII字符,传不了二进制附件
- URL:有些特殊字符在URL里有特殊含义(? & =),二进制数据传不了
- HTML/CSS:在网页里直接嵌入图片,不需要额外请求
- JSON/XML:这些文本格式不能直接塞二进制数据
Base64就是把二进制数据”翻译”成纯文本,安全地通过这些通道。
二、原理

每3个字节(24位)分成4组,每组6位,查表得到4个字符。
原始数据:Man
二进制:01001101 01100001 01101110
6位分组:010011 011000 010110 1110(补00)
查表:T W F u
结果:TWFu
如果原始数据不是3的倍数:
剩1个字节 → 输出2个字符 + 2个 “=” 填充
剩2个字节 → 输出3个字符 + 1个 “=” 填充
任何二进制数据都可以,不只是PNG
图片:PNG、JPG、GIF、WEBP、SVG、BMP、ICO
音频:MP3、WAV、AAC、OGG
视频:MP4、AVI、WEBM
文档:PDF、ZIP、EXE、DLL
证书:PEM格式的SSL证书
任意文件:任何你能想到的文件
三、其他编码
Base16(Hex):用16个字符(0-9 A-F),体积膨胀100%
Base32:用32个字符,体积膨胀约60%
Base64:用64个字符,体积膨胀约33%
一张100KB的PNG图片:
base64编码后约133KB
解码后恢复为原始的100KB PNG
Base85:用85个字符,体积膨胀约25%,但字符集更复杂
Base64是体积和可读性的最佳平衡点
四、使用示例
package main
import (
"encoding/base64"
"fmt"
"os"
)
func main() {
//1. 基础字符串编解码
original := "Hello, 世界! "
fmt.Printf("原始字符串: %s\n", original)
encoded := base64.StdEncoding.EncodeToString([]byte(original))
fmt.Printf("Base64编码: %s\n", encoded)
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
fmt.Printf("解码错误: %v\n", err)
} else {
fmt.Printf("Base64解码: %s\n", string(decoded))
}
// 2. URL安全的Base64
urlData := "user+name/test=data&key=val"
fmt.Printf("原始数据: %s\n", urlData)
stdEncoded := base64.StdEncoding.EncodeToString([]byte(urlData))
urlEncoded := base64.URLEncoding.EncodeToString([]byte(urlData))
fmt.Printf("标准Base64: %s\n", stdEncoded)
fmt.Printf("URL Base64: %s\n", urlEncoded)
// 3. 无填充的Base64
data := "abc"
fmt.Printf("原始数据: %s\n", data)
fmt.Printf("带填充: %s\n", base64.StdEncoding.EncodeToString([]byte(data)))
fmt.Printf("无填充: %s\n", base64.RawStdEncoding.EncodeToString([]byte(data)))
// 4. 自定义Base64字母表
custom := base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!")
customEncoded := custom.EncodeToString([]byte("Hello World"))
fmt.Printf("自定义编码: %s\n", customEncoded)
customDecoded, _ := custom.DecodeString(customEncoded)
fmt.Printf("自定义解码: %s\n", string(customDecoded))
// 5. 模拟图片Base64编码
// 创建一个假的PNG文件头(实际项目中替换为真实图片文件)
fakePNG := []byte{
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, // PNG文件头
0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, // IHDR
}
imgEncoded := base64.StdEncoding.EncodeToString(fakePNG)
fmt.Printf("图片Base64: %s\n", imgEncoded)
// 模拟HTML内嵌(取前min(30, len)个字符)
prefixLen := 30
if len(imgEncoded) < prefixLen {
prefixLen = len(imgEncoded)
}
fmt.Printf("HTML内嵌: <img src=\"data:image/png;base64,%s...\" />\n", imgEncoded[:prefixLen])
// 6. 读真实文件并编码(如果存在)
filename := "/tmp/test_base64.txt"
os.WriteFile(filename, []byte("这是一个测试文件内容\n用于演示Base64编码"), 0644)
content, err := os.ReadFile(filename)
if err != nil {
fmt.Printf("读文件失败: %v\n", err)
} else {
fileEncoded := base64.StdEncoding.EncodeToString(content)
fmt.Printf("文件名: %s\n", filename)
fmt.Printf("原始大小: %d 字节\n", len(content))
fmt.Printf("编码大小: %d 字节\n", len(fileEncoded))
fmt.Printf("膨胀率: %.1f%%\n", float64(len(fileEncoded)-len(content))/float64(len(content))*100)
fmt.Printf("Base64: %s\n", fileEncoded)
}
os.Remove(filename)
// 7. 错误处理 - 非法Base64
invalidBase64 := "ThisIsNot@Valid#Base64!"
_, err = base64.StdEncoding.DecodeString(invalidBase64)
if err != nil {
fmt.Printf("非法Base64 '%s' 解码错误: %v\n", invalidBase64, err)
}
// 8. 严格模式
// 标准模式允许尾部bits非零
loose := base64.StdEncoding
strict := base64.StdEncoding.Strict()
testData := "SGVsbG8=" // "Hello"
_, err1 := loose.DecodeString(testData)
_, err2 := strict.DecodeString(testData)
fmt.Printf("标准模式解码 '%s': %v\n", testData, err1)
fmt.Printf("严格模式解码 '%s': %v\n", testData, err2)
// 9. 编解码长度计算
for _, n := range []int{1, 2, 3, 4, 5, 6, 10, 100} {
encLen := base64.StdEncoding.EncodedLen(n)
decLen := base64.StdEncoding.DecodedLen(encLen)
fmt.Printf("输入%3d字节 → 编码%4d字节 → 解码最多%3d字节\n", n, encLen, decLen)
}
}