HandyTools Hub

← 全部指南

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–25AZ
26–51az
52–6109
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 里的经典例子):

  1. 三个字符的 ASCII 码分别是 M=77、a=97、n=110;
  2. 写成二进制拼起来:01001101 01100001 01101110(共 24 比特);
  3. 按 6 比特切开:010011010110000101101110
  4. 转成十进制:19、22、5、46;
  5. 查字母表: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 字符”的本质,下次在任何地方再遇到这串字符,你都知道它在干什么——以及如何亲手把它还原出来。