Base64编码规则

栏目: JavaScript · 发布时间: 7年前

内容简介:Base64编码规则

网络信息传递时,一些二进制资源往往需要转换为Base64编码进行传输,以提高传输效率,例如webpack提供了将图片格式文件转换为Base64格式,下面将简单介绍Base64编码的原理和实现过程。

Base64编码原理

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。base64要求将每三个8bits字节转换为四个6bit的字节(3 * 8 = 4 * 6 = 24),然后将转换后的6bit往高位添加2个0,组成4个8bit的字节,再根据这4个8bit字节的十进制在索引表中查找对应的值,此时得到的结果就是Base64值。

因此,理论上, 转换后的字符串的长度要比原来的字符串长度长1/3 ,例如:转换前的4*6二进制字符串为:aaaaaa bbbbbb cccccc dddddd,在每个字节高位添加两个零后就是: 00aaaaaa 00bbbbbb 00cccccc 00dddddd,此时长度就比原字符串长度多了1/3。

一下是一段话编码为Base64前后的变化:

编码前:

Man is distinguished, not only by his reason, but by this singular passion from
other animals, which is a lust of the mind, that by a perseverance of delight
in the continued and indefatigable generation of knowledge, exceeds the short
vehemence of any carnal pleasure.

编码后:

TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz
IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg
dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu
dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo
ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=

前面提到了Base64算法的索引表,Base64的索引表由64个ASCII字符组成:0-9,26个英文小写字母a-z,26个英文大写字母:A-Z,除此之外还有额外两个字符”+”和”/”。下面是Base64的索引表:

Base64编码规则

理论上上面的索引表还要加入padding:”=”,前面提到一个字符串转成Base64时是生成4个字符,如果待转换的字符串转换后不足4个Base64字符,则空白的地方需要使用“=”补充,看下面的例子就能明白:

文本”M”转换为Base64的过程:

Base64编码规则

在这里,”M”转换后的ASCII不足以填充够24位二进制字符串,再第二个字节之后,全部用”0”补充,得到的索引值即分别为”T”,”Q”,”=”,”=”,最终的Base64编码结果为”TQ==”.

再来看两个个例子加深印象,字符串”Ma”:

Base64编码规则

转换后的Base64结果为:”TWE=”。

字符串”Man”:

Base64编码规则

转换后结果为”TWFu”。

这里进行一个小结,普通字符串文本转换为Base64的基本过程为:

字符串对应的字符转换为ASCII→将该ASCII转换为8位二进制→将转换的8位二进制进行6bit拆分,高位填充0,形成新的二进制→根据新的二进制从Base64索引表查找结果

Base64编码的实现

了解了Base64的转换规则后,我们通过JavaScript来简单实现Base的 编码 以及 解码 :

var Base64 = {

_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

//将字符串转换为Base64
encode: function(input) {
    var output = "";
    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    var i = 0;

    while (i < input.length) {

        chr1 = input.charCodeAt(i++);
        chr2 = input.charCodeAt(i++);
        chr3 = input.charCodeAt(i++);

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;

        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }
        output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
    }
    return output;
},

//将Base64解码为可读字符串
decode: function(input) {
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;

    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

    while (i < input.length) {
        enc1 = this._keyStr.indexOf(input.charAt(i++));
        enc2 = this._keyStr.indexOf(input.charAt(i++));
        enc3 = this._keyStr.indexOf(input.charAt(i++));
        enc4 = this._keyStr.indexOf(input.charAt(i++));

        chr1 = (enc1 << 2) | (enc2 >> 4);
        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
        chr3 = ((enc3 & 3) << 6) | enc4;

        output = output + String.fromCharCode(chr1);

        if (enc3 != 64) {
            output = output + String.fromCharCode(chr2);
        }
        if (enc4 != 64) {
            output = output + String.fromCharCode(chr3);
        }
    }
    return output;
	}
}

首先定义一个Base64的索引值 _keyStr ,其中包含了A-/的64个字符,最后还加上填充值’=’,索引值供编码以及解码时使用。

首先看编码方法(encode),定义输入原始字符串的连续三个字符chr1,chr2,chr3,输出的4个二进制字符enc1,enc2,enc3,enc4,通过一个变量 i 遍历输入的原始字符串,以原始字符串“abcd”为例:

第一次循环: 首先将第一次循环的三个字符转变为ASCII的十进制模式

chr1 = input.charCodeAt(i++);//chr1:a→97
chr2 = input.charCodeAt(i++);//chr2:b→98
chr3 = input.charCodeAt(i++);//chr3:c→99
console.log(chr1)//97(0110 0001)
console.log(chr2)//98(0110 0010)
console.log(chr3)//99(0110 0011)

有了ASCII的十进制值后,即可使用 位运算 ,将 3 * 8 的二进制拆分为4 * 6的二进制模式,下面一步一步来看位运算是如何实现4 * 6拆分的:

enc1 = chr1 >> 2;
/*计算enc1:将chr1右移两位:0110 0001→0001 1000*/
console.log(enc1)//00011000

enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
/*计算enc2:
/*取chr1的最后两位作为enc2的最高位,取chr2的高四位作为enc2的低四位,将两者通过或运算结合:
/*( chr1 & 3 ) << 4= (0110 0001 & 0000 0011) << 4 = (00000001)<<4 = 0001 0000,
/*(chr2 >> 4) = (0110 0010) >> 4 = 00000110,
/*enc2=0001 0000 | 0000 0110=0001 0110
/*console.log(enc2)//00010110
*/

enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
/*计算enc3:
/*取chr2的低四位和chr3的高两位组成enc2的低六位(高两位补零): 
/*(chr2 & 15) << 2 = (0110 0010 & 0000 1111) << 2 = 0000 0010 << 2 = 0000 1000, 
/*chr3 >> 6 = 0110 0011 >> 6 = 0000 0001,
/*enc3 = 0000 1000 | 0000 0001 = 0000 1001
/*console.log(enc3)//00001001
*/

enc4 = chr3 & 63;
/*计算enc4:取chr3余下六位作为低六位(高两位补零):
/*enc4 = 0110 0011 & 0011 1111 = 0010 1011
/*console.log(enc4)//00101011
*/

此时通过 this._keyStr.charAt(encx) 进行索引查找,得到的前三个字符的编码为 “YWJj”

分析完 "abcd""abc" 编码,也就是程序的第一次循环,还剩”d”未解析,此时需要进入第二次循环,由于d之后已经没有字符,故第二次循环时的 chr1chr2chr3 的结果为: 100 , NaN , NaN 。同理进行3 * 8 = 4 * 6编码时得到的最后编码为“ZA==”。

经过两次循环后,原始字符串”abcd”已经被全部遍历并编码,最后得到的Base64编码为”YWJjZA==”。

理解了 encode 方法后,再去进行解码’decode’就比较简单了,基本上就是编码的逆向操作,这里就不一一解释了。

总结

Base64作为一种传输二进制的编码格式,虽然编码后字符内容长度会增加大约1/3,但是在一定程度上保证了一些不可打印字符在传输时的的信息完整性,同时本文最后也通过使用JavaScript实现了Base64的编码以及解码,可以看到Base64也起到了一定的加密作用(起码不是人一眼就能看懂的),在实际项目中应根据具体需求和环境选用Base64编码。

(完)

参考资料:

Base64

Base64 algorithm


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法神探

算法神探

[美] 杰瑞米·库比卡 / 啊哈磊、李嘉浩 / 电子工业出版社 / 2017-2 / 65

《算法神探:一部谷歌首席工程师写的CS小说》围绕程序设计典型算法,精心编织了一个扣人心弦又趣味横生的侦探缉凶故事。小说主人公运用高超的搜索技巧和精深的算法知识,最终识破阴谋、缉拿元凶。其间,用二分搜索搜查走私船、用搜索树跟踪间谍、用深度优先搜索逃离监狱、用优先队列开锁及用最佳优先搜索追寻线索等跌宕起伏又富含算法精要的情节,让读者在愉悦的沉浸式体验中快速提升境界,加深对程序世界的理解。《算法神探:一......一起来看看 《算法神探》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具