Base64 编码是一种将二进制数据转换为 ASCII 字符的编码方式,也就是将二进制数据文本化。
为什么需要Base64编码
- 早期网络协议的限制:一些SMTP、HTTP 等协议最初设计只支持 ASCII 字符,图片、音频、文件等二进制数据包含大量非 ASCII 字节(如 0x80 以上的数值)在传输的过程中会出现协议解析错误、字符集不兼容的问题。(对于一些网络应用层协议,虽然支持选择非 ASCII 码的字符集,但是在传输数据的过程中还有图片、音频等二进制数据,在解码时都可能会出现字符集兼容问题)
- 保证数据传输的准确性:避免二进制数据在传输的过程中被错误的解析,例如一些特殊字符会被误解析。
Base64编码原理
Base64 编码过程主要是分组和字节重组,具体步骤如下:
- 将待转换的字符串每 3 个字节作为一组,总计 24 位。
- 将 24 位数据每 6 位作为一组,共分为 4 组,不足补 0。
- 每组转换为十进制,在 Base64 字符表找到数值对应的字符
- 若总字节数非 3 的倍数,原始数据字节数非 3 的倍数时,需补 0 至 3 的倍数。每补 2 字节(16 位)对应 1 个
=,补 1 字节(8 位)对应 2 个=。
Base64 字符表如下:
0-25: A-Z, 26-51: a-z, 52-61: 0-9, 62: +, 63: /
注:选取 3 个字节和 6 位一组的原因是:6位即为 2^6 = 64,此处选择3个字节一组和6位一组是因为8位和6位刚好是24的公倍数),64 位刚好可以表示 52 个包含大小写的英文字母以及 10 个数字以及两个特殊字符,刚好符合 ASCII 码的编码范围
举两个例子:
例1(无需填充):
- 原始数据: abc
- 二进制表示:每个字符占 1 字节,共 3 字节
011000010110001001100011 - 6 位一组分割二进制流:
011000(24)、010110(22)、001001(9)、100011(35) - 查 Base64 字符表映射为对应字符:
24→Y、22→W、9→J、35→k, 刚好 3 个字节是 6 的整数倍,因此无需填充
最终的编码结果为:YWJj
例2(需要填充):
- 原始数据: a
- 二进制表示:每个字符占 1 字节,共 1 字节
01100001 - 补全 3 字节:
011000010000000000000000 - 6 位一组分割二进制流:
011000(24)、010000(16)、000000(0)、000000(0) - 查 Base64 字符表映射为对应字符:
24→Y、16→Q, 后两组为补 0 生成,需用=替代无效字符
最终的编码结果为:YQ==
Base64编码常用场景
- 电子邮件附件传输
- API 接口中的二进制数据传输
- URL 与配置文件中的数据传递
Base64 编码的缺点
- Base64编码会导致数据膨胀。3 字节原始数据编码为 4 字节 Base64 字符串,长度增加约 33%;
- Base64编码不是加密算法,只是一种可逆的编码方式,不能替代加密。
实际踩的坑:
- URL 的入参如果在经过 Base64 编码后生成数据中包含
=,此时在日志中打印的 URL 会通过URL 编码规则将=转换为%3D。因为 URL 中不能直接包含某些特殊字符(如=、空格、&等),这些字符在 URL 中具有特殊语义(如=用于分隔参数名和值,&用于分隔参数对)。为了让特殊字符能安全传输,需将其转换为百分号编码(Percent-Encoding) 格式。
一些想法:
如果双方需要交换一些物品(包括数据),这些物品又存在多种样式,在交换的过程中很难进行衡量。那么就可以考虑使用一个中间层的物品,将各种样式的物品都转换为中间层的物品,这样交换起来就不会存在价值无法衡量或数据无法转换的情况了。在接收到物品以后,再按照各自的规则将中间层物品转换为自己所需的物品(例如 Base64 编码就在网络传输中扮演着这么一个角色)。