Base64编码探究

目录

概念

  Base64编码是网络传输中的一种常见编码方式。可用于传输任意的8bit(字节Byte)数据,经过编码后的数据不是直接可读的,但也由此保证了一定的安全性和很好的可移植性。这种编解码的算法十分简单,编码后的数据大小仅增加三分之一左右(原因后续讲到),因而不会对传输造成过大压力。
  我们需要明确的概念是,Base64编码本质上是将二进制数据编码为文本字符。而这些二进制数据的来源则可能有很多,比如:

  • 本来就是二进制数据
  • 本来是英文字母或数字,则有对应的ASCII编码,ASCII表一般会表示为十进制和十六进制的值,自然也有对应的二进制值
  • 本来是汉字,可能是多种编码得到的,比如采用UTF-8编码得到,则该汉字的UTF-8编码的值可以用二进制表示

上述各种类型的文本转换为二进制后,就可以使用Base64进行编码了。


官方规范

  Base64编码是作为MIME多用途互联网邮件扩展标准的一部分进行开发的。MIME RFC 2045的6.8节详细介绍了这种编码方式,参见http://www.ietf.org/rfc/rfc2045.txt.pdf,这是Base64编码的官方规范。


Base64字母表

由名字也可以看出,Base64编码将任意字符转换为用下表64个字符(中的某些)进行表示(具体原理稍候分析)。

图中最后的(pad) =是Base64编码中使用的填充字符,用于补足,在后面的原理分析中会看到。


原理

  之前已经提到过Base64编码是对“字节数据”做处理。一个字节是8bit,也就是8个二进制位。假设现在有一个英文字符串,每个字符由1个字节(8bit)构成,则对应了一个字节序列。Base64编码将这些8位的字节序列拆分成多个6位的片段,计算这个6位二进制数对应的十进制值,根据该十进制值查Base64字母表,使用表中的字符指代该片段。(2^6=64,64种符号刚好可以表示6位二进制数的全部情况。)下面展示了一个具体的例子:

  通过这样的分析,我们也就可以知道为什么Base64编码字符串比原始字符串扩大约三分之一:原来一个字符用8位表示,现在6位就代表一个字符,所以扩大(8-6)/6=1/3。
  
  还有一个问题需要考虑:8位的字节序列不一定总能分割成整数个6位的片段。这时候,为了正常编码,就要在原序列末尾补足,使得序列长度成为24的倍数(6,8的最小公倍数):

  • 如果要进行补足的6位片段中包含原序列的位,则使用0补足,构成的6位二进制数按照正常情况进行查表得出对应的编码字符。
  • 如果要进行补足的6位片段中包含原序列的位(即这个片段的6位都是用来补足的,并不含原数据),则这个片段编码为填充字符=
    如下示例:

应用

Base64编码有很广泛的应用:

  1. 用户输入文本数据可通过Base64编码打包后作为HTTP首部字段的值发送给服务端

  2. HTML5的FileAPI进行文件读取的示例如下:

    1
    2
    3
    4
    5
    6
    7
    // 读取文件:
    var reader = new FileReader();
    reader.onload = function(e) {
    var data = e.target.result;
    preview.style.backgroundImage = "url(" + data + ")";
    preview.style.backgroundSize ='300px 200px';
    };

其中变量data保存的是’image/jpeg;base64,/9j/4AAQSk……’这就是典型的Base64编码。编码值作为url()方法的参数去设置background-image。

注:url()方法不仅可以接受文件路径作为参数,也可以传入上述的这种data类型url,主要有以下几种:
data:,<文本数据>
data:text/plain,<文本数据>
data:text/html,
data:text/html;base64,
data:text/css,
data:text/css;base64,
data:text/javascript,
data:text/javascript;base64,
data:image/gif;base64,base64编码的gif图片数据
data:image/png;base64,base64编码的png图片数据
data:image/jpeg;base64,base64编码的jpeg图片数据
data:image/x-icon;base64,base64编码的icon图片数据

3.上面提到过,Base64编码是作为邮件协议进行开发的。电子邮件一般使用SMTP协议将邮件从客户端发往服务端,使用POP3或者IMAP从服务端获取邮件。最初SMTP协议基于纯ASCII文本,对二进制数据(文件)支持不好,为了解决这个问题,有了base64编码,即对二进制数据进行编码得到ASCII串使其能够正常通过SMTP协议进行传输。Content-Transfer-Encoding: base64表示附件文件内容使用base64编码后传输。

4.HTTP请求需要携带参数,比如GET方法是直接在url中进行参数拼接,这些可能需要转换为适合通过HTTP进行传输的数据,这就可以使用Base64编码。但是,经过Base64编码得到的文本中会包含+ /这样的符号,而这些会在URL编码时被转义,因此还有一些变种的Base64编码,比如它不仅在末尾填充’=’号,并将标准Base64中的“+”和“/”分别改成了“-”和“_”,这样就免去了在URL编解码和数据库存储时所要作的转换。


JavaScript实现

  使用原生js的实现比较麻烦,这里推荐一个类库js-base64