一串 Base64 摆在面前时,最先能看到的往往是开头那几个固定字母:PNG 转出来一定是 iVBORw0KGgo,JPEG 一定是 /9j/。这不像是巧合,但它也不是设计美学,而是三十多年前"邮件服务器只肯传 7 位 ASCII"这个约束留下的痕迹。这篇讲这条线:问题最早出在哪,base64 这个名字第一次出现在哪份文档,字母表顺序为什么是 A-Z、a-z、0-9、+、/,定稿之后又长出了哪几个分支。
看的时候有个前提值得记住:今天你在浏览器、接口、配置文件里碰到的 Base64,规则和 1993 年那份文档几乎没有差别。所以下面每个时间节点,都能对应到你现在正在做的某个动作。
一、根子上的麻烦:邮件只认 7 位 ASCII
1982 年的 SMTP(RFC 821)把邮件传输设计成一封封 ASCII 文本。网关、老主机、字符集转换设备会重写它们看不懂的字节:0x00 到 0x1F 那批控制字符会被当成指令处理,带 NUL 的字节直接被吞掉,图片的二进制尾巴传过去就短了一截。附件因此经常以乱码或者被截断的形式到达收件人那里。
一路上不会被动过的字符只有可打印 ASCII,不到一百个。办法只能是反向的:把任意字节重新写成这一小撮安全字符,接收方再倒推回原始字节。你今天用 文件转 Base64 做的动作,和当年给附件想办法的邮件工程师做的是同一件事。
时间线上还有一件事容易搞错:SMTP 支持 8 位内容(8BITMIME 扩展)要到 1994 年的 RFC 1652 才写进规范,而且就算有了它,转发链路上仍然有设备只做 7 位清洗。把二进制转成文本这条路没有被废掉,一直用到了今天。
二、base64 这个名字第一次出现:RFC 1421(1993)
RFC 1421 是隐私增强邮件的规范,1993 年发布。它为了把加密后的二进制报文塞进邮件正文,定义了一种叫 base 64 的表示法:每 6 个 bit 一组,每组取值 0 到 63,对应一张 64 个字符的表。表的内容就是 A 到 Z、a 到 z、0 到 9,最后加上 + 和 /。
这个顺序不是随便排的。索引从小到大,字符按 ASCII 递增,于是"索引大、字符也大",比较和排序都省事:0 是 A,25 是 Z,26 起是小写,52 起是数字,62 和 63 交给 + 与 /。后来的 RFC 3548、RFC 4648 都原样继承了这张表。
三、MIME 让它成了事实标准(1992—1996)
真正让 Base64 走出"一份隐私扩展文档"的是 MIME。1992 年的 RFC 1341 给邮件加上多类型内容的能力,1993 年的 RFC 1521 把它整理成一份,1996 年 MIME 重新编号为 RFC 2045 到 2047,其中 base64 被写成 Content-Transfer-Encoding 的合法取值之一,和 quoted-printable 并列。
邮件头里那行 Content-Transfer-Encoding: base64 就是这条规定的遗留。折行规则也定在同一时期:每行最多 76 个字符,超出就断行。今天你把一段 Base64 粘进代码里,报"非法字符"的成因有一半出在这些换行上。
想看结构化文本变成 Base64 之后的样子,JSON 转 Base64 是最省事的对照。
四、脱离邮件:RFC 2397、RFC 3548、RFC 4648
1998 年的 RFC 2397 定义 Data URL,把数据直接写进 URI,Base64 是它承载二进制的方式。浏览器由此可以在 HTML 里内联一张图片,不用再发第二个请求。
2003 年的 RFC 3548 做了件更关键的事:把 base16、base32、base64 从邮件规范里抽出来,写成与传输场景无关的通用数据编码,并且给文件名和 URL 场景加了 base64url 变体,用 - 和 _ 顶掉 + 和 /。2006 年的 RFC 4648 取代 3548,术语理得更干净,明确填充符 = 可以省略,还专门写了一节安全性考虑,说清这只是编码、不提供任何机密性。
你现在要查"Base64 规范",应该打开的就是 RFC 4648。
五、定稿之后长出的几个分支
- base64url 与无填充变体:JWT(RFC 7519,2015 年)用 base64url 且不带 =,塞进 HTTP 头和 query 时不用再转义。
- Base85 / ASCII85:5 个字符表达 4 个字节,体积只涨 25%。RFC 1924(1996 年)拿它压缩 IPv6 地址,Git 编码部分对象名时也在用。
- Base32:字符表只有 A-Z 和 2-7,故意避开 0、1、8、9 这些容易看错的形状,给人工抄写和语音报读留路,一次性口令的密钥常写成这个样子。
- Base58:在 Base58 字符表上继续去掉易混淆字符,比特币地址用它。
六、三件 1993 年定下、至今没变的事
- 字母表还是那 64 个字符,顺序也一样。
- 3 字节换 4 字符的分组方式没变,所以输出长度一定是 4 的倍数。
- 填充符还是 =,缺几个字节决定它出现一次还是两次。
正因为这些规则稳定,你可以靠开头猜类型。PNG 的 8 字节签名(89 50 4E 47 0D 0A 1A 0A)编出来就是 iVBORw0KGgo,任何一张 PNG 转 Base64 都是这 11 个字符打头,用 PNG 转 Base64 拿自己手头的图试,次次都对得上。JPEG 打头是 /9j/,PDF 打头是 JVBER,来自文件头的 %PDF-。这些固定前缀只是文件开头那段字节被编码后的样子,用来判断真实格式比看扩展名可靠。
速查小结
- Base64 诞生于邮件只能安全传 7 位 ASCII 的限制,目的是把任意字节写成一小撮不会被中间设备改动的字符。
- 名字和字母表出自 1993 年的 RFC 1421,MIME(RFC 2045,1996)让它成为附件的事实标准。
- RFC 3548(2003)把它通用化,RFC 4648(2006)是当前标准,同时定义了 base64url。
- 字母表顺序、3 字节换 4 字符、= 填充这三件事从 1993 年到现在没变过。
- 它至今只是编码:64 个字符的表任何人都能反推,不承担保密。
要对照上面任何一条,直接把文本或文件粘进 Base64 在线编码解码,看输出长度是不是 4 的倍数、结尾有没有 =、开头能不能认出熟悉的前缀。