Base64编码是一种将字节数据编码为字符串的编码,字节数据会被编码成由64个可打印ASCII字符组成的字符串,这64个字符包括大写字母A-Z, 小写字母a-z, 以及数字 0 -9再加上 + 和 / ,恰好64个字符。对应的字符表以下图:前端
base64编码的一个用途就是对http的头信息进行编码,因为http头信息使用ASCII编码,若是包含特殊字符可能会致使头信息解析异常,采用base64编码保证头信息只包含一些简单字符,提升了安全性。前端在显示图片元素时也常常会遇到base64编码的图片资源。数组
那么base64具体是如何进行编码的呢?浏览器
编码方式很简单,就是对目标字节中的每六个bit位表示为字母表中的某个字符,例如:安全
‘abc’对应的二进制字节为: 01100001 , 01100010 , 01100011 ; 每六位进行分组获得的结果以下:async
011000, 010110, 001001, 100011,转化为10进制就是:24,22, 9, 35,根据上面的字母表获得各个数字对应的字符为:YWJj,因此abc最终会被编码为 ‘YWJj’。因为三个字节最终被编码成了四个字节的字符串,因此长度增长了1/3.编码
看着这里你们可能会有一个问题,假设原数据的字节长度不是3的倍数,就会有剩余的bit位不够6个字符,这是就会涉及到填充的问题,填充就是在原数据后面加上额外的冗余位,使数据的bit位长度恰好能被24(也就是3个字节)整除(6和8的最小公倍数)。具体的填充规则能够简单的表述为: 任何彻底填充(不包含原始数据中的位) 的 6 位组都由特殊的第 65 个符号“=” 表示。 若是 6 位组是部分填充的, 就将填充位设置为 0(http权威指南)。spa
举个例子:假设在编码的过程当中原数组有四个字节,这时就须要再填充2个字节。假设最后的两个bit为是10,填充后的数据的最后几位以下:code
10 xxxx, xxxxxx,xxxxxx (x表明填充位)blog
根据前面描述的填充规则:第一个6位组对应的数字为 10 0000,后面两个因为时彻底填充的,被编码为==,最终的结果的后三位就变成了‘g==’。图片
在浏览器端,能够调用全局的方法 atob 和 btoa 实现二进制字符与base64编码的字符之间的互相转化。下面给出一个base64编码前端实现的简单例子:
const table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; // 参数为待编码的字符串 async function toBase64(str) { const blob = new Blob([str], { type: 'text/plain' }); // 获取字节长度,也可使用第三方库提供的同步方法 // 这里为了演示简单 const srcBuf = await blob.arrayBuffer(); // 获取原数据的字节长度 const length = blob.size; // 计算须要填充的位数 const padLen = length % 3 === 1 ? 2 : length % 3 === 2 ? 1 : 0; // 最终的长度 const size = length + padLen; const arrBuf = new ArrayBuffer(size); const srcArray = new Uint8Array(srcBuf); const dstArray = new Uint8Array(arrBuf); for (let i = 0; i < size; i++) { if (i < length) { dstArray[i] = srcArray[i]; } else { dstArray[i] = 0x00; } } let result = []; // 每次处理3个字节 for (let i = 0; i < size; i += 3) { // 取出三个字节 const a = dstArray[i]; const b = dstArray[i + 1]; const c = dstArray[i + 2]; // 最后一组 const isLast = i + 3 > length; console.log(padLen) result.push(a >> 2); // 第一个字节的前6位 result.push(((a & 0b00000011) << 4) | (b >> 4)); // 第一个字节的后两位加上第二个字节的前四位 // 第二个字节的后四位加上的三个字节的前两位 if (!isLast || padLen === 0) { result.push(((b & 0b00001111) << 2) | (c >> 6)); result.push(c & 0b00111111); // 第三个字节的后六位 } else { if (padLen === 2) { result.push('=', '='); } else if (padLen === 1) { result.push(((b & 0b00001111) << 2) | (c >> 6), '='); } } } result = result.map(code => code === '=' ? '=' : table[code]).join(''); return result; }
base64转二进制字节原理相似,有兴趣的童鞋能够自行尝试!!
实际的运行效果以下图: