百度百科中对Base64有一个很好的解释:“Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法”。

    什么是“可打印字符”呢?为什么要用它来传输8Bit字节码呢?在回答这两个问题之前我们有必要来思考一下什么情况下需要使用到Base64?

    Base64一般用于在HTTP协议下传输二进制数据,由于HTTP协议是文本协议,所以在HTTP协议下传输二进制数据需要将二进制数据转换为字符数据。然而直接转换是不行的。因为网络传输只能传输可打印字符

    什么是可打印字符?在ASCII码中规定,0~31、127这33个字符属于控制字符,32~126这95个字符属于可打印字符,也就是说网络传输只能传输这95个字符,不在这个范围内的字符无法传输。那么该怎么才能传输其他字符呢?其中一种方式就是使用Base64(2^6 = 64 < 95,2^7=128 > 95,所以取64)。

    Base64,就是使用64个可打印字符来表示二进制数据的方法。Base64的索引与对应字符的关系如下表所示(如下为标准对应关系,自定义对应关系则可一定程度上进行加密,实际上不是加密,加解码时两边的字符表一致即可):
    image.jpeg

    也就是说,如果将索引转换为对应的二进制数据的话需要至多6个Bit。然而ASCII码需要8个Bit来表示,那么怎么使用6个Bit来表示8个Bit的数据呢?6个Bit当然不能存储8个Bit的数据,但是46个Bit可以存储38个Bit的数据啊!如下表所示:
    image.jpeg

    可以看到“Son”通过Base64编码转换成了“U29u”。这是刚刚好的情况,3个ASCII字符刚好转换成对应的4个Base64字符(38 = 46)。但是,当需要转换的字符数不是3的倍数的情况下该怎么办呢?Base64规定,当需要转换的字符不是3的倍数时,一律采用补0的方式凑足3的倍数(往后补0),具体如下表所示:

    image.jpeg
    每6个Bit为一组,第一组转换后为字符“U”,第二组末尾补4个0转换后为字符“w”。剩下的使用“=”替代。即字符“S”通过Base64编码后为“Uw==”。这就是Base64的编码过程。

    补0的时候若6bit中仍有真实数据的部分(2bit),仍需要进行查表转换,即使真实数据为0,相应的Base64字符也应对应A,只有6bit全是自动添加的才能为=。
    a:a — 011000 010011 101001 100001 — YTph
    a:aa — 011000 010011 101001 100001 011000 01xxxx xxxxxx xxxxxx — YTphYQ==
    a:aaa — 011000 010011 101001 100001 011000 010110 0001xx xxxxxx — YTphYWE=
    a:aaaa — 011000 010011 101001 100001 011000 010110 000101 1000001— YTphYWFh

    由于标准的Base64编码后可能出现字符+和/,在URL中就不能直接作为参数,所以又有一种”url safe”的base64编码,其实就是把字符+和/分别变成-和_。

    由于=字符也可能出现在Base64编码中,但=用在URL、Cookie里面会造成歧义,所以,很多Base64编码后会把=去掉,但去掉=后怎么解码呢?因为Base64是把3个字节变为4个字节,所以,Base64编码的长度永远是4的倍数,因此,需要加上=把Base64字符串的长度变为4的倍数,就可以正常解码了。

    • ASCII 是用128(2的8次方)个字符,对二进制数据进行编码的方式
    • base64编码是用64(2的6次方)个字符,对二进制数据进行编码的方式
    • base32就是用32(2的5次方)个字符,对二进制数据进行编码的方式
    • base16就是用16(2的4次方)个字符,对二进制数据进行编码的方式