Base64 编码

204 阅读4分钟

Base64 编码是一种将二进制数据转换为 ASCII 字符的编码方式,也就是将二进制数据文本化。

为什么需要Base64编码

  1. 早期网络协议的限制:一些SMTP、HTTP 等协议最初设计只支持 ASCII 字符,图片、音频、文件等二进制数据包含大量非 ASCII 字节(如 0x80 以上的数值)在传输的过程中会出现协议解析错误、字符集不兼容的问题。(对于一些网络应用层协议,虽然支持选择非 ASCII 码的字符集,但是在传输数据的过程中还有图片、音频等二进制数据,在解码时都可能会出现字符集兼容问题)
  2. 保证数据传输的准确性:避免二进制数据在传输的过程中被错误的解析,例如一些特殊字符会被误解析。

Base64编码原理

Base64 编码过程主要是分组和字节重组,具体步骤如下:

  1. 将待转换的字符串每 3 个字节作为一组,总计 24 位。
  2. 将 24 位数据每 6 位作为一组,共分为 4 组,不足补 0。
  3. 每组转换为十进制,在 Base64 字符表找到数值对应的字符
  4. 若总字节数非 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 字节 01100001 01100010 01100011
  • 6 位一组分割二进制流:011000(24)、010110(22)、001001(9)、100011(35)
  • 查 Base64 字符表映射为对应字符:24→Y22→W9→J35→k, 刚好 3 个字节是 6 的整数倍,因此无需填充
    最终的编码结果为YWJj

例2(需要填充):

  • 原始数据: a
  • 二进制表示:每个字符占 1 字节,共 1 字节 01100001
  • 补全 3 字节:01100001 00000000 00000000
  • 6 位一组分割二进制流:011000(24)、010000(16)、000000(0)、000000(0)
  • 查 Base64 字符表映射为对应字符:24→Y16→Q, 后两组为补 0 生成,需用=替代无效字符
    最终的编码结果为:YQ==

Base64编码常用场景

  1. 电子邮件附件传输
  2. API 接口中的二进制数据传输
  3. URL 与配置文件中的数据传递

Base64 编码的缺点

  1. Base64编码会导致数据膨胀。3 字节原始数据编码为 4 字节 Base64 字符串,长度增加约 33%;
  2. Base64编码不是加密算法,只是一种可逆的编码方式,不能替代加密。

实际踩的坑:

  1. URL 的入参如果在经过 Base64 编码后生成数据中包含=,此时在日志中打印的 URL 会通过URL 编码规则=转换为%3D。因为 URL 中不能直接包含某些特殊字符(如=、空格、&等),这些字符在 URL 中具有特殊语义(如=用于分隔参数名和值,&用于分隔参数对)。为了让特殊字符能安全传输,需将其转换为百分号编码(Percent-Encoding)  格式。

一些想法:

如果双方需要交换一些物品(包括数据),这些物品又存在多种样式,在交换的过程中很难进行衡量。那么就可以考虑使用一个中间层的物品,将各种样式的物品都转换为中间层的物品,这样交换起来就不会存在价值无法衡量或数据无法转换的情况了。在接收到物品以后,再按照各自的规则将中间层物品转换为自己所需的物品(例如 Base64 编码就在网络传输中扮演着这么一个角色)。