Base64 到底是什么:为什么图片会变成一串字符
2026-08-06
如果你看过网页源代码,大概率见过这样的东西:<img> 标签的 src 属性里不是图片路径,而是一大串以 iVBORw0KGgo 开头、由字母数字加号斜杠组成、偶尔以 = 结尾的字符。那就是 Base64——一张图片被”翻译”成了纯文本。为什么要这么做?这串字符是怎么算出来的?这篇文章从编码原理讲起,把每个常见疑问逐个解开。
先回答根本问题:为什么需要 Base64
计算机里的所有数据本质上都是字节,一个字节是 8 个比特,取值 0–255。但很多传输场景是为文本设计的:电子邮件协议(SMTP)早期只保证 7 位 ASCII 能安全通过,JSON、XML、URL 里也有很多”不能出现”的字符——二进制数据里随机的字节值一旦混进去,轻则被篡改,重则直接截断。
Base64 的思路很直接:只使用 64 个公认安全的可打印字符来表示任意二进制数据。这 64 个字符在任何文本系统里都能原样通过,于是图片、证书、加密密钥这些二进制内容就能塞进文本协议里传输了。
64 个字符的字母表
Base64 标准(RFC 4648)的字母表是:
| 索引范围 | 字符 |
|---|---|
| 0–25 | A–Z |
| 26–51 | a–z |
| 52–61 | 0–9 |
| 62 | + |
| 63 | / |
每一个字符恰好对应 0–63 的一个值,也就是 6 个比特(2⁶ = 64)。这是理解 Base64 的唯一关键:它用每个字符携带 6 位信息。
编码过程:3 字节变 4 字符
一个字节是 8 比特,一个 Base64 字符携带 6 比特。8 和 6 的最小公倍数是 24,所以编码以 3 字节(24 比特)为一组,切成 4 段各 6 比特,每段查字母表变成一个字符。这就是”3 字节变 4 字符”的由来。
拿字符串 Man 走一遍完整流程(这也是 RFC 4648 里的经典例子):
- 三个字符的 ASCII 码分别是
M=77、a=97、n=110; - 写成二进制拼起来:
01001101 01100001 01101110(共 24 比特); - 按 6 比特切开:
010011、010110、000101、101110; - 转成十进制:19、22、5、46;
- 查字母表:19→
T、22→W、5→F、46→u。
所以 Man 的 Base64 编码是 TWFu。你可以把这个词粘进 Base64 编解码工具 验证,结果一模一样。解码就是逆过程:每个字符查回 6 比特,拼起来再按 8 比特分组还原成字节。
为什么体积会膨胀约 33%
算一笔账就够了:3 字节的原始数据编码后变成 4 个字符,而文本里每个字符占 1 字节,所以编码后是 4 字节。4 ÷ 3 ≈ 1.333,即体积恰好膨胀三分之一。一张 300 KB 的图片转成 Base64 大约变成 400 KB 的文本。
这解释了为什么业界不建议把大图片做成 Base64 内联到 HTML 里:除了体积变大,浏览器还必须先下载完整 HTML 才能开始解码,失去了并行加载和缓存的机会。Base64 内联适合的是小图标、小占位图这类几 KB 的内容。
= 是填充,不是数据的一部分
输入的字节数不总是 3 的倍数。剩下 1 个字节(8 比特)时,能凑出 2 个 6 比特段(12 比特,后 4 位补零),编码成 2 个字符,再补两个 =;剩下 2 个字节时编码成 3 个字符,补一个 =。所以 Base64 字符串的末尾只有三种可能:没有 =、一个 =、两个 =,绝不会更多。
看两个例子:M(1 字节)编码为 TQ==,Ma(2 字节)编码为 TWE=。= 只是告诉解码器”最后一组不满 3 字节”的占位符。顺带一提,有些场景会省略填充字符(比如 JWT),解码时需要自己补回去——这是”这段 Base64 怎么解不出来”的常见原因之一。
URL-safe 变体:把 + 和 / 换掉
标准字母表里的 + 和 / 在 URL 里有特殊含义(+ 在查询串里会被解释成空格),直接放进链接会出问题。于是 RFC 4648 同时定义了 Base64url 变体:用 - 替换 +,用 _ 替换 /,并且通常省略末尾的 =。JWT(JSON Web Token)用的就是它——你看到的 eyJhbGci... 开头的三段式 token,每一段都是 Base64url。
如果你拿到一段 Base64 解码报错,先检查里面有没有 - 或 _:有的话说明它是 URL-safe 变体,需要把这两个字符换回来再解码。
Base64 不是加密,也不是压缩
这是最需要澄清的误解。Base64 是一种编码(encoding),不是加密(encryption):编码规则完全公开,任何人拿到字符串都能在毫秒内还原原文,整个过程不需要密钥。把密码、密钥”用 Base64 加密一下再存”等于明文存储——攻击者看到 = 结尾的字符串,第一反应就是解一把试试。
它同样不提供任何压缩效果,反而如前面算过的那样让数据变大 33%。判断一段字符串是不是 Base64 也很简单:长度是 4 的倍数,字符全部落在 A-Za-z0-9+/ 加可选 = 的范围内。想亲手确认,随手把可疑字符串丢进编解码工具解码看看,是 Base64 的话原文立刻现形。
data URI:Base64 最经典的用途
Base64 最常见的露面方式是 data URI,格式是:
data:[<媒体类型>][;base64],<数据>
比如把一张 PNG 小图标直接内联进 HTML:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..." alt="icon">
或者在 CSS 里内联一张背景图:
.logo {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0...");
}
好处是少一次 HTTP 请求:图片跟着 HTML/CSS 一起到达,对小图标这类高频小资源很划算;坏处前面说过——体积大 33%,且不能被浏览器单独缓存。实践中通常只对几 KB 以内的小图这么做。转换本身很简单,用图片转 Base64 工具上传图片就能直接拿到完整的 data URI,不用自己拼 data:image/png;base64, 这个前缀。
除了 data URI,Base64 还活跃在很多地方:邮件附件(MIME)、API 里传输二进制字段(比如证书、签名、缩略图)、Kubernetes 配置文件里的 Secret 值、以及前面提到的 JWT。理解了它”3 字节变 4 字符”的本质,下次在任何地方再遇到这串字符,你都知道它在干什么——以及如何亲手把它还原出来。