接口报文里一长串以 = 结尾的乱码、HTML 里 data:image/png;base64, 开头的图片地址,都是 Base64。它常被误解为「加密」,这篇先纠正这个误会,再讲怎么正确用它。
Base64 的作用是把任意二进制数据用 64 个可打印字符表示出来(A–Z、a–z、0–9、+、/)。任何文件——图片、压缩包、中文文本——在它眼里都是字节序列,转完任何人都能原样还原。它没有密钥、不保密,只解决「二进制数据在纯文本环境里怎么安全传输」的问题:邮件协议、JSON 报文、URL 参数、CSS 内嵌,这些场景不允许出现乱码字节,Base64 让二进制「伪装」成普通文本。
1 字节 = 8 位,3 字节 = 24 位。24 位刚好拆成 4 个 6 位组,每个 6 位组(0–63)查表对应一个字符。所以 Base64 把每 3 字节编码成 4 字符,体积膨胀 33%。这也是它不适合大文件的原因——一张 3MB 的图编码后约 4MB,还要额外占内存解码。
结尾的 = 是补位符:数据长度不是 3 的倍数时,最后剩 1 字节补 2 个 =,剩 2 字节补 1 个 =。所以 = 最多出现两个,看到它就知道这段编码「尾部有零头」。
| 场景 | 建议 |
|---|---|
| ≤ 2KB 的小图标、loading 动画帧 | 值得内嵌:省一次 HTTP 请求,渲染更快 |
| 10KB 以上的正常图片 | 不要内嵌:体积 +33%,且无法被浏览器缓存独立复用 |
| 多个页面共用的图 | 不要内嵌:每页都带一份,白白重复传输 |
正确用法是在 CSS 里写 background-image: url(data:image/png;base64,xxxx),或 HTML 里 <img src="data:image/png;base64,xxxx">。注意 data: 前缀和 MIME 类型(png/jpeg/svg)必须写对,否则图片不显示。
拿经典例子 "Man" 走一遍。三个字母的 ASCII:M=77、a=97、n=110,写成二进制分别是 01001101、01100001、01101110。拼成 24 位串:010011 010110 000101 101110。每组 6 位转十进制:19、22、5、46。查 Base64 表(A=0,B=1……Z=25,a=26……):19=T、22=W、5=F、46=u。所以 "Man" 编码后是 TWFu——和标准库输出一致。
如果原文长度不是 3 的倍数,比如 "Ma" 只有两个字节 16 位,补两个 0 凑成 18 位得 3 个字符,再补一个 = 凑满 4 字符,输出 "TWE="。这个例子能解释你见到的一切 Base64 特征:为什么输出长度总是 4 的倍数、= 为什么只出现在结尾、为什么同样内容每次编码结果都一样(它是确定性映射,与加密的本质区别)。
问:Base64 里的 + 和 / 在 URL 里出问题怎么办?
URL 场景用变体「Base64URL」:+ 换成 -,/ 换成 _,去掉补位 =。JWT 令牌用的就是它。
问:为什么解码后中文变乱码?
Base64 只负责字节级还原,乱码出在字符集环节——编码前必须先按 UTF-8 把文本转字节,解码后也按 UTF-8 还原,两端口径不一致就会出现乱码。