虽然名字听起来像是某种“64进制”,但实际上它是一种编码方式,不是数学意义上的“进制”

起源背景

Base64 最早起源于电子邮件协议 MIME(Multipurpose Internet Mail Extensions),因为早期的电子邮件系统只能传输 ASCII 文本,不能直接传输二进制数据(如附件)。于是人们发明了 Base64 编码方法,把二进制数据转换成文本形式,从而安全地在网络上传输

标准的 Base64

Base64 不是一种加密算法,而是一种编码方式

就是基于 64 个可打印字符来表示二进制数据的方法:

  • 小写字母 a-z
  • 大写字母 A-Z
  • 数字 0-9
  • 符号 +/

编码规则

  1. 把 3 个字节变成 4 个字节
  2. 每 76 个字符加一个换行符
  3. 最后的结束符也要处理

如:

  • 原字符串 s13
  • 转成 ascii 对应:115, 49, 51
  • 二进制: 01110011, 00110001, 00110011
  • 6 个一组(4 组): 011100, 110011, 000100, 110011
  • 计算机一个字节占 8 位,不够高位补 0:00011100, 00110011, 00000100, 00110011
  • 得到:28, 51, 4, 51
  • 对照表:czEz

原文的字节数量应该是 3 的倍数,如果这个条件不能满足的话,具体的解决办法是这样的:原文剩余的字节根据编码规则继续单独转(1 变 2,2 变 3;不够的位数用 0 补全),再用 = 补满 4 个字节。

这就是为什么有些 Base64 编码会以一个或两个等号结束的原因,但等号最多只有两个。因为一个原字节至少会变成两个目标字节,所以余数任何情况下都只可能是 0,1,2 这三个数中的一个:

  • 如果余数是 0 的话,就表示原文字节数正好是 3 的倍数(最理想的情况)
  • 如果是 1 的话,转成 2 个 Base64 编码字符,为了让 Base64 编码是 4 的倍数,就要补 2 个等号
  • 同理,如果是 2 的话,就要补 1 个等号

注意

Base64 并非压缩算法,它会将数据体积增加约 33%

应用

场景说明
图片嵌入到 HTML/CSS 中Data URI 方式减少请求
JSON 数据中传输二进制信息如头像、加密数据等
WebSocket 发送二进制消息避免使用 ArrayBuffer
二维码生成将图像转为 Base64 存储

很多下载类网站都提供“迅雷下载”的链接,其地址通常是加密的迅雷专用下载地址。其实迅雷的“专用地址”也是用 Base64 “加密”的,其过程如下:

  1. 在地址的前后分别添加 AAZZ
  2. 对新的字符串进行 Base64 编码

另外 Flashget 的与迅雷类似,只不过在第一步时加的“料”不同罢了,Flashget 在地址前后加的“料”是 [FLASHGET]

而 QQ 旋风的干脆不加料,直接就对地址进行 Base64 编码了

Base64 URL

标准的 Base64 并不适合直接放在 URL 里传输,因为 URL 编码器会把标准 Base64 中的 +/ 字符变为形如 %XX 的形式,而这些 % 在存入数据库时还需要再进行转换,因为 ANSI SQL 中已将 % 号用作通配符。

为解决此问题,可采用一种用于 URL 的改进 Base64 编码,它在末尾填充 =,并将标准 Base64 中的 +/ 分别改成了 -_,这样就免去了在 URL 编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。

浏览器提供了 btoa 函数,可以将字符串转换成 Base64 URL 字符串;反之也提供了 atob 函数

node 没有提供这两个函数,可以安装第三方库 atobbota,或者自己写

Base64 其他变种

另有一种用于正则表达式的改进 Base64 变种,它将 +/ 改成了 !-,因为 +/ 在正则表达式中都具有特殊含义。

此外还有一些变种,它们将 +/ 改为 _-._(用作编程语言中的标识符名称)或 .-(用于 XML 中的 Nmtoken)甚至 _:(用于 XML 中的 Name)。