在网络编程和后端开发中,我们经常会看到 Base64 的身影,例如 HTTP、JSON、JWT、邮件附件、图片上传等场景。
很多人第一次接触 Base64 时容易产生一个误解:
Base64 是一种加密算法吗?
实际上,Base64 不是加密,而是一种编码方式。
它的核心作用是:将二进制数据转换成由有限字符组成的文本数据,从而方便在只适合传输文本的场景中传输二进制内容。
本文将从 Base64 的基本概念出发,详细介绍 Base64 的编码原理、解码过程、填充机制、数据膨胀问题,以及它在实际开发中的应用。
一、什么是 Base64?
Base64 是一种基于 64 个字符的二进制数据编码方式。
它可以将任意二进制数据转换成可打印的 ASCII 字符,例如:
text
Hello
经过 Base64 编码后:
text
SGVsbG8=
再进行 Base64 解码:
text
SGVsbG8=
↓
Hello
因此,Base64 本质上是一个可逆的编码过程:
text
Base64 编码
二进制数据 ─────────→ 文本字符串
↑ │
│ │
└──── Base64 解码 ────┘
需要特别强调:
Base64 不提供安全性,也不能用于保护敏感数据。
因为任何人都可以很容易地对 Base64 字符串进行解码。
例如:
text
YWRtaW46MTIzNDU2
进行 Base64 解码后就是:
text
admin:123456
所以,如果需要保护数据,应使用 AES、RSA 等加密算法,而不是 Base64。
二、为什么需要 Base64?
计算机中的数据本质上都是二进制:
text
01001000 01100101 01101100 01101100 01101111
但是,在很多网络协议和数据格式中,更适合传输的是文本。
例如 JSON:
json
{
"name": "Tom"
}
如果直接把一段二进制数据放进 JSON,就可能出现:
text
0x00
0xFF
0x1A
...
这些数据中可能包含不可打印字符或者特殊控制字符,不方便直接作为文本传输。
于是就可以使用 Base64:
text
二进制数据
↓
Base64 编码
↓
ASCII 字符串
↓
JSON / HTTP / XML 等文本协议
例如图片可以转换成:
json
{
"image": "iVBORw0KGgoAAAANSUhEUg..."
}
这样,原本的二进制图片就变成了普通字符串。
因此,Base64 解决的核心问题可以概括为:
如何把任意二进制数据安全、统一地表示成文本字符。
这里的"安全"指的是传输格式上的安全和兼容性,而不是密码学意义上的安全。
三、Base64 为什么是 64 个字符?
Base64 使用 64 个字符来表示数据:
text
A-Z
a-z
0-9
+
/
一共:
text
26 + 26 + 10 + 1 + 1 = 64
为什么恰好是 64 个?
因为:
text
2^6 = 64
也就是说:
6 个 bit 可以表示 64 种不同的值。
因此,一个 Base64 字符实际上对应:
text
6 bit
例如:
text
0 → A
1 → B
2 → C
...
25 → Z
26 → a
27 → b
...
51 → z
52 → 0
...
61 → 9
62 → +
63 → /
这就是 Base64 的核心字符映射表。
四、Base64 的核心编码原理
Base64 最核心的一句话就是:
每 3 个字节(24 bit)划分成 4 组,每组 6 bit,然后分别映射成一个 Base64 字符。
原始数据中:
text
1 Byte = 8 bit
Base64 一个字符:
text
1 字符 = 6 bit
因此:
text
3 Byte
= 3 × 8 bit
= 24 bit
然后:
text
24 bit
↓
4 × 6 bit
↓
4 个 Base64 字符
整个过程可以表示为:
text
原始数据:
┌────────┬────────┬────────┐
│ 8 bit │ 8 bit │ 8 bit │
└────────┴────────┴────────┘
24 bit
│
▼
┌──────┬──────┬──────┬──────┐
│ 6bit │ 6bit │ 6bit │ 6bit │
└──────┴──────┴──────┴──────┘
│ │ │ │
▼ ▼ ▼ ▼
0~63 0~63 0~63 0~63
│ │ │ │
▼ ▼ ▼ ▼
Base64 字符
这就是 Base64 最核心的工作机制。
五、通过 Hello 理解 Base64
下面通过 Man 这个字符串完整理解 Base64 的编码过程。
1. 获取 ASCII 编码
text
M = 77
a = 97
n = 110
转换成二进制:
text
M = 01001101
a = 01100001
n = 01101110
拼接:
text
01001101 01100001 01101110
一共 24 bit。
2. 每 6 bit 进行分组
将 24 bit 按照 6 bit 重新划分:
text
010011 010110 000101 101110
分别转换成十进制:
text
010011 = 19
010110 = 22
000101 = 5
101110 = 46
3. 根据 Base64 字符表进行映射
根据 Base64 字符表:
text
19 → T
22 → W
5 → F
46 → u
所以:
text
Man
↓
TWFu
整个过程:
text
Man
↓
01001101 01100001 01101110
↓
010011 010110 000101 101110
↓
19 22 5 46
↓
T W F u
↓
TWFu
这就是 Base64 编码。
六、Base64 为什么会出现 =?
在实际使用中,经常可以看到这样的字符串:
text
SGVsbG8=
最后的 = 是什么?
它叫做:
Padding(填充字符)
Base64 希望每次处理:
text
3 Byte → 4 个字符
但是原始数据长度不一定刚好是 3 的倍数。
例如:
text
Hello
一共有 5 个字节。
可以拆成:
text
Hel + lo
其中:
text
Hel = 3 Byte
lo = 2 Byte
第一组可以正常转换。
第二组只有 2 Byte:
text
16 bit
不足 24 bit,因此需要补 0,使其能够按照 6 bit 进行划分。
最终产生 3 个有效 Base64 字符,第四个位置使用:
text
=
进行填充。
因此:
text
Hello
↓
SGVsbG8=
七、Base64 的填充规则
Base64 的填充规则非常简单。
| 原始数据长度 | Base64 结果 |
|---|---|
| 3 的整数倍 | 不需要 = |
| 余 1 字节 | 最后增加 == |
| 余 2 字节 | 最后增加 = |
例如:
text
M
↓
TQ==
Ma
↓
TWE=
Man
↓
TWFu
可以总结为:
text
原始数据长度 % 3
0 → 无填充
1 → ==
2 → =
需要注意的是,= 并不是实际的数据内容,而是用于表示数据长度和补齐编码结果。
八、Base64 为什么会增加数据量?
Base64 有一个非常明显的缺点:
编码后的数据会变大。
原因很简单。
原始数据:
text
3 Byte = 24 bit
经过 Base64:
text
4 个字符
如果按照一个字符 1 Byte 计算:
text
4 Byte
所以:
text
4 / 3 ≈ 1.333
也就是说:
Base64 编码后的数据理论上会增加约 33.3%。
例如:
text
原始数据:300 MB
Base64:约 400 MB
实际数据由于填充等因素会有少量差异。
因此,对于大型二进制数据,例如:
- 视频
- 音频
- 大型图片
- 大文件
如果传输链路本身支持二进制数据,通常没有必要先转换成 Base64。
否则会造成:
text
数据量增加
↓
网络带宽增加
↓
传输时间增加
↓
内存占用增加
九、Base64 编码和解码过程
Base64 编码:
text
原始二进制
│
▼
每 3 Byte 分组
│
▼
24 bit
│
▼
拆成 4 个 6 bit
│
▼
转换成 0~63
│
▼
查 Base64 字符表
│
▼
Base64 字符串
Base64 解码则完全相反:
text
Base64 字符串
│
▼
查 Base64 字符表
│
▼
得到 0~63
│
▼
转换成 6 bit
│
▼
4 × 6 bit = 24 bit
│
▼
还原成 3 Byte
│
▼
原始二进制数据
因此 Base64 是完全可逆的。
十、Base64 与 Hex 的区别
在开发过程中,Base64 和十六进制 Hex 都可以用于表示二进制数据。
例如:
text
Hello
对应的 ASCII 十六进制:
text
48 65 6C 6C 6F
Base64:
text
SGVsbG8=
两者的主要区别:
| 对比项 | Base64 | Hex |
|---|---|---|
| 使用字符数量 | 64 | 16 |
| 每个字符表示 | 6 bit | 4 bit |
| 数据膨胀 | 约 33% | 约 100% |
| 网络传输效率 | 较高 | 较低 |
| 可读性 | 一般 | 较好 |
| 二进制调试 | 一般 | 非常常见 |
所以可以简单理解:
Base64 更适合二进制数据的文本化传输。
而:
Hex 更适合查看、打印和调试二进制数据。
十一、Base64 在实际开发中的应用
1. HTTP
Base64 经常出现在 HTTP 场景中。
例如 HTTP Basic Authentication:
http
Authorization: Basic YWRtaW46MTIzNDU2
其中:
text
YWRtaW46MTIzNDU2
实际上就是:
text
admin:123456
经过 Base64 编码后的结果。
但是 Base64 不具备加密能力,因此 Basic Authentication 通常需要配合 HTTPS 使用。
2. JSON
JSON 本身是文本格式,如果需要传递二进制数据,可以使用 Base64:
json
{
"data": "SGVsbG8="
}
服务端收到之后:
text
SGVsbG8=
↓
Base64 Decode
↓
二进制数据
3. 图片
网页或者接口中经常可以看到:
text
data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...
这里的:
text
iVBORw0KGgoAAAANSUhEUg...
就是图片经过 Base64 编码后的内容。
4. JWT
JWT 中也大量使用 Base64URL。
一个典型 JWT:
text
xxxxx.yyyyy.zzzzz
实际上由三部分组成:
text
Header.Payload.Signature
其中 Header 和 Payload 使用的是 Base64URL 编码。
注意:
JWT 中的 Base64URL 也不是加密。
所以不要认为 JWT 的 Payload 因为经过 Base64URL 编码,就无法被别人看到。
十二、Base64URL 是什么?
标准 Base64 使用:
text
+
/
=
但是 +、/、= 在 URL 中存在特殊含义,因此在 URL 场景中通常使用 Base64URL。
Base64URL 通常做以下转换:
text
+ → -
/ → _
同时通常会去掉末尾的:
text
=
例如:
text
标准 Base64
TWFu+abc/xyz=
Base64URL:
text
TWFu-abc_xyz
JWT 使用的就是这种变体。
十三、从程序员角度理解 Base64
如果从 C/C++ 开发的角度理解,可以把 Base64 看成两个函数:
cpp
Base64Encode()
Base64Decode()
例如原始数据:
cpp
uint8_t data[] = {
0x48, 0x65, 0x6c, 0x6c, 0x6f
};
对应:
text
48 65 6C 6C 6F
经过 Base64 编码:
text
SGVsbG8=
再解码:
text
SGVsbG8=
↓
48 65 6C 6C 6F
因此在网络程序中,如果看到一个 Base64 字符串,可以首先判断:
text
Base64字符串
↓
Base64 Decode
↓
二进制数据
↓
根据实际协议继续解析
这一点在协议分析、网络抓包和流媒体开发中尤其重要。
十四、Base64 的优缺点
优点
1. 可以将二进制数据转换成文本
适合:
text
HTTP
JSON
XML
邮件
配置文件
等文本场景。
2. 字符集简单
主要使用:
text
A-Z
a-z
0-9
+
/
=
兼容性比较好。
3. 编码和解码简单
Base64 算法本身非常简单,CPU 开销通常较低。
缺点
1. 数据量增加
理论上增加约:
text
33.3%
2. 不是加密
Base64 可以非常容易地被解码。
3. 不适合大型二进制数据的无意义转换
例如视频文件:
text
原始视频
↓
Base64
↓
数据增加约 33%
↓
网络传输
如果网络协议本身支持二进制传输,就没有必要这么做。
十五、Base64 原理总结
Base64 的核心其实非常简单:
text
原始数据
│
▼
3 Byte = 24 bit
│
▼
┌────┬────┬────┬────┐
│6bit│6bit│6bit│6bit│
└────┴────┴────┴────┘
│ │ │ │
▼ ▼ ▼ ▼
0~63 0~63 0~63 0~63
│ │ │ │
▼ ▼ ▼ ▼
Base64字符表
│
▼
文本字符串
可以记住下面几个关键点:
第一,Base64 是编码,不是加密。
第二,Base64 的核心是 3 字节转 4 字符。
第三,原始数据每 3 个字节会被拆成 4 组 6 bit。
第四,6 bit 可以表示 64 种状态,因此叫 Base64。
第五,数据长度不是 3 的倍数时,需要使用 = 进行填充。
第六,Base64 编码后数据量通常增加约 33%。
因此,一句话总结 Base64:
Base64 就是将二进制数据每 3 个字节组成 24 bit,再划分成 4 个 6 bit,并通过 64 个可打印字符进行映射,从而将二进制数据转换成文本字符串的一种编码方式。