把字节写成文本的四种方式

Base16(hex)、Base32、Base64 和百分号编码都解决一个问题:用纯文本通道能安全传输的字符来表示数据。它们在两个相互权衡的轴上有所不同,字母表大小体积开销。更大的字母表每个字符打包更多位,所以输出更短;更小或更受限的字母表更易读或在给定情境中更安全,但输出更长。前三种在 RFC 4648 中一起定义;百分号编码来自 RFC 3986,工作方式与其余的不同。

一眼看懂体积开销

对于原始二进制输入,RFC 4648 三种编码的膨胀是固定且可预测的:

编码           位/字符    比率               开销
Base16         4          2 字符 / 字节      +100%
Base32         5          8 字符 / 5 字节    +60%
Base64         6          4 字符 / 3 字节    +33%

Base64 最紧凑,Base16 最不。百分号编码是个例外:它根本不是固定比率。它让非保留字符保持不动,只把其余的每个扩展为三个字符,所以它的开销完全取决于内容。对于主要是字母和数字的文本,它几乎是免费的;对于原始二进制,几乎每个字节都需要转义,它飙升到约 +200%,比其他任何一种都差。

字母表与可读性

  • Base16 / hex 使用 0-9A-F。一个字节始终是两个字符,所以字节边界完全清晰。它最易于用眼睛读取和比较,这就是为什么哈希、密钥和十六进制转储都用它。
  • Base32 使用 A-Z2-7,大小写不敏感,去掉了易混淆的字符 018。它是为人会输入、口述或在不区分大小写的情况下存储的值而设计的,比如 密钥和 onion 地址。
  • Base64 使用 A-Za-z0-9+/,大小写敏感。它是三者中最密的,但 +/ 在 URL 和文件名中不安全,而 URL 安全变体修复了这一点。
  • 百分号编码让可读文本保持可读,只转义 URL 无法按字面传输的部分。它是一种转义方案,而非完整的重新编码。

该选哪一个

选择取决于通道和受众。如果必须读取、输入或比较该值,优先选 hex(用于检查字节)或 Base32(用于输入或口述)。如果机器必须通过文本通道搬运任意字节且大小重要,使用 Base64,或当值在 URL、文件名或令牌内传输时使用 Base64URL。如果你在把文本放入 URL 而只有少数字符不安全,就对它进行百分号编码,而不是重新编码一切。

一条快速规则:紧凑用 Base64,输入用 Base32,读取用 hex,URL 用百分号编码。

试试它们

codec 工具运行全部四种。粘贴任意文本,切换编码,并排比较输出,每种都有解码,全部在你的浏览器中完成。