Base64、Base64URL 与 Data URI
了解 Base64 编码的用途、为什么会增大约 33%、URL 安全变体的区别,以及 Data URI 的适用场景。
Base64 是什么(又不是什么)
Base64 使用 64 个安全的 ASCII 字符——A–Z、a–z、0–9、加号 + 和斜杠 /——对任意二进制数据进行编码,使它能够通过只接受文本的通道,例如 JSON 请求体、电子邮件、XML、HTTP 请求头和环境变量。它是编码,不是加密:任何人都能立即解码,不提供任何保密性。
代价是体积变大。Base64 每次处理 3 个字节并映射为 4 个字符,因此输出通常比输入大约 33%,还要加上填充。通过 Base64 发送一个 10 MB 的文件,实际需要传输约 13.3 MB。
填充和 = 符号
由于输入很少能恰好按 3 个字节分组,输出会用 = 填充到 4 的倍数。剩余 1 个输入字节会产生 xx==,剩余 2 个字节会产生 xxx=。因此 Base64 字符串末尾可能有 0、1 或 2 个等号,但不会有 3 个。
大多数解码器认为填充只是装饰,这也是 URL 安全场景经常去掉填充的原因。不过某些严格解析器要求保留填充,因此同时接受带填充和不带填充的解码器更实用。
Base64URL:适合网络的变体
标准 Base64 的 + 和 / 会破坏 URL(查询字符串中的 + 通常表示空格,/ 会分隔路径)。RFC 4648 定义了 Base64URL:用 - 替换 +,用 _ 替换 /,并且通常省略填充。JSON Web Token 使用的就是这个变体——JWT 的三个点分隔片段分别是 Base64URL 编码的 JSON——URL 安全标识符也常用它。
如果包含 - 或 _ 的输入解码时报“invalid character”,说明你拿到的是 Base64URL,而解码器期待标准 Base64,或者反过来。
Data URI
Data URI 可以把资源直接内嵌到 HTML 或 CSS 中,例如 data:image/png;base64,iVBOR.... 逗号前的部分声明 MIME 类型,并说明后面的内容是 Base64 载荷。这样小型资源(网站图标、小图标、内联 SVG 后备内容)可以省去一次 HTTP 请求,但代价是额外增加约 33% 的体积,而且无法单独缓存。
一个实用的经验法则是:资源小于几 KB 时可以考虑 Data URI;再大一些时,带内容哈希名称、可以独立缓存的文件在各项指标上都更合适。
先处理 UTF-8
Base64 编码的是字节,不是字符。如果不指定 UTF-8 就直接编码包含重音符号、Emoji 或中日韩文字的字符串,另一端会得到乱码;浏览器中的 atob() 处理国际化文本时出现问题,通常就是这个原因。正确流程是:字符串 → UTF-8 字节 → Base64,解码时反向执行。
参考资料
相关工具
- Base64 编解码器在浏览器本地编码和解码 Base64 与 Base64URL。
- URL 编解码器安全地编码和解码 URL 组件及查询字符串。
- JWT 解码器在本地解码 JWT 的头部和载荷,不进行签名校验。