Base64 主要有以下作用:
一、作用
-
数据传输
- 在网络通信中,Base64 可以将二进制数据编码为 ASCII 字符,使得数据可以在只支持文本传输的通道中进行传输,比如在电子邮件中传输图片、在 HTTP 请求中传输二进制数据等。
- 避免了一些字符集不兼容的问题,确保数据能够在不同系统和平台之间可靠地传输。
-
数据存储
- 在某些情况下,将二进制数据编码为 Base64 可以更方便地存储在文本文件或数据库中,而不需要专门的二进制存储机制。
-
URL 和文件名安全
- Base64 编码后的字符串不包含特殊字符,因此可以安全地用于 URL 参数或文件名,不会引起解析错误。
二、关于数据大小变化
Base64 编码通常会使数据大小增加约 33%。这是因为 Base64 使用 64 个可打印的 ASCII 字符来表示二进制数据,每个 6 位的 Base64 编码单元对应 8 位的原始二进制数据。具体计算如下:
- 8 位二进制数据可以表示 2 8 = 256 2^8 = 256 28=256 个不同的值。
- 6 位 Base64 编码可以表示 2 6 = 64 2^6 = 64 26=64 个不同的值。
- 所以,每 3 个字节(24 位)的原始数据会被编码为 4 个 Base64 字符(24 位),即编码后的数据长度是原始数据长度的 4 / 3 4/3 4/3 倍,增加了约 1 / 3 1/3 1/3,也就是 33%。
需要注意的是,虽然 Base64 编码会增加数据大小,但在某些特定场景下,为了满足数据传输或存储的要求,这种增加是可以接受的。同时,不同类型的数据在经过 Base64 编码后的大小变化可能会有所不同,但大致都在这个比例左右。
一、Base64 的 64 个字符
Base64 使用的 64 个字符包括大写字母 A-Z、小写字母 a-z、数字 0-9 以及两个特殊字符“+”和“/”。具体如下:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
二、编码规则
- 首先将需要编码的二进制数据按每 6 个比特为一组进行分组。如果最后一组不足 6 个比特,则在末尾用 0 补齐,使其成为 6 的倍数。
- 对于每一组 6 个比特,根据其值在上述 64 个字符中找到对应的字符进行编码。
- 如果原始数据的长度不是 3 的倍数,那么在编码后的结果末尾可能会有“=”作为填充字符。具体填充规则如下:
- 如果原始数据长度除以 3 的余数是 1,则在编码结果末尾添加两个“=”。
- 如果余数是 2,则在编码结果末尾添加一个“=”。
例如,对于字符串“Man”进行 Base64 编码:
- 首先将“Man”转换为 ASCII 码值对应的二进制表示:
- M 的 ASCII 码值为 77,二进制为 01001101。
- a 的 ASCII 码值为 97,二进制为 01100001。
- n 的 ASCII 码值为 110,二进制为 01101110。
- 将这三个字符的二进制拼接起来得到:01001101 01100001 01101110。
- 按每 6 个比特一组进行分组:010011、010110、000101、101110。
- 分别将每组转换为十进制值:19、22、5、46。
- 对照 Base64 的 64 个字符表,找到对应的字符:T、W、F、u。
- 所以“Man”的 Base64 编码结果为“TWFu”。
三、Base64 解码规则
- 首先,识别出 Base64 编码的字符串中的有效字符(即大写字母 A-Z、小写字母 a-z、数字 0-9、“+”和“/”)。
- 将每个有效字符转换为对应的 6 位二进制值。例如,“A”对应 000000,“B”对应 000001,以此类推。
- 将这些 6 位二进制值按顺序拼接起来,每 8 位一组,转换为对应的 ASCII 码值,从而得到原始的二进制数据。
- 如果编码字符串末尾有“=”填充字符,则在解码时忽略这些填充字符,并根据填充字符的数量确定需要丢弃的二进制位。如果末尾有一个“=”,则丢弃最后 4 个二进制位;如果末尾有两个“=”,则丢弃最后 8 个二进制位。
四、举例说明
以 Base64 编码字符串“TWFu”为例进行解码:
- 首先确定每个字符对应的 6 位二进制值:
- “T”对应 010100。
- “W”对应 010111。
- “F”对应 000111。
- “u”对应 011101。
- 将这些二进制值拼接起来得到:010100010111000111011101。
- 按每 8 位一组进行划分:01001101、01100001、01101110。
- 将这些 8 位二进制值转换为 ASCII 码值,得到:77(M)、97(a)、110(n)。
所以,“TWFu”解码后得到的原始数据为“Man”。
将二进制数据编码为 ASCII 字符主要有以下几个原因:
一、兼容性和通用性
- ASCII 字符集是一种广泛被接受和理解的字符编码标准。许多系统、软件和通信协议都能很好地处理 ASCII 字符。通过将二进制数据编码为 ASCII 字符,可以确保数据在不同的环境和平台中具有更好的兼容性和通用性。
- 例如,在电子邮件系统中,只允许传输 ASCII 字符。如果要发送二进制数据(如图片、音频文件等),就需要将其编码为 ASCII 字符,以便能够在电子邮件中顺利传输。
二、文本传输通道的限制
- 在一些通信场景中,只支持文本传输。比如 HTTP 请求通常是基于文本的,如果要在 HTTP 请求中传输二进制数据,就需要将其编码为 ASCII 字符,以便能够在 HTTP 协议中正确传输。
- 网络中的很多中间设备(如防火墙、代理服务器等)可能对非 ASCII 字符的二进制数据进行过滤或限制。将二进制数据编码为 ASCII 字符可以避免这些问题,确保数据能够顺利通过各种网络设备。
三、可读性和可调试性
- ASCII 字符是人类可读的,这使得编码后的数据在一定程度上具有可读性。在调试和排查问题时,可以更容易地理解和分析编码后的数据。
- 例如,如果在网络传输中出现问题,可以通过查看编码后的 ASCII 字符来初步判断数据是否完整或是否存在错误,而不需要直接处理难以理解的二进制数据。
不编码为 ASCII 字符在某些特定情况下也是可以的,但会面临很多问题:
- 如果不编码为 ASCII 字符,数据可能无法在只支持文本传输的通道中传输,导致通信失败。
- 不同系统和平台对非 ASCII 字符的二进制数据的处理方式可能不同,可能会导致兼容性问题。
- 在一些场景下,非 ASCII 字符的二进制数据可能会被错误地解释或截断,影响数据的完整性。
综上所述,将二进制数据编码为 ASCII 字符在很多情况下是必要的,可以提高数据的兼容性、通用性和可传输性。
当原始数据长度不是 3 的整数倍时,Base64 编码和解码过程如下:
一、编码过程
假设原始数据为“Ma”,只有两个字符。
- 首先将“Ma”转换为 ASCII 码值对应的二进制表示:
- M 的 ASCII 码值为 77,二进制为 01001101。
- a 的 ASCII 码值为 97,二进制为 01100001。
- 将这两个字符的二进制拼接起来得到:0100110101100001。
- 由于长度不足 3 个字节,在末尾补两个 0,变为:010011010110000100。
- 按每 6 个比特一组进行分组:010011、010110、000100。
- 前三个组分别转换为十进制值:19、22、4。
- 对照 Base64 的 64 个字符表,找到对应的字符:T、W、E。
- 由于最后一组不足 6 个比特,且原始数据长度除以 3 的余数是 2,所以在编码结果末尾添加一个“=”,最终编码结果为“TWE=”。
二、解码过程
对于编码结果为“TWE=”的字符串进行解码。
- 首先识别出有效字符“T”“W”“E”,忽略末尾的“=”。
- 将每个有效字符转换为对应的 6 位二进制值:
- “T”对应 010100。
- “W”对应 010111。
- “E”对应 000100。
- 将这些二进制值拼接起来得到:010100010111000100。
- 由于末尾有一个“=”,说明原始数据长度除以 3 的余数是 2,所以丢弃最后 4 个二进制位,得到:0100110101100001。
- 将这个 16 位二进制值按每 8 位一组进行划分:01001101、01100001。
- 将这些 8 位二进制值转换为 ASCII 码值,得到:77(M)、97(a)。
所以,“TWE=”解码后得到的原始数据为“Ma”。