base64编码简介及简单实现

Base64编码是一种将字节数据编码为字符串的编码,字节数据会被编码成由64个可打印ASCII字符组成的字符串,这64个字符包括大写字母A-Z, 小写字母a-z, 以及数字 0 -9再加上 + 和 / ,恰好64个字符。对应的字符表以下图:
image.png前端

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转二进制字节原理相似,有兴趣的童鞋能够自行尝试!!
实际的运行效果以下图:

image.png

相关文章
相关标签/搜索