前言
在浏览器中,可以借助函数:btoa(),来对字符串进行base64的编码。
btoa()函数的返回值是经过编码成功之后的base64字符串。
btoa()函数支持二进制数据作为输入,也就是单字节表示的字符,如果你的字符串中包含了非单字节的字符,那么这个函数会报错
可以利用atob进行解码
背景知识
ASCII码
ASCII码由一个字节表示(8位),ASCII码中最大码值是127
utf-8
utf-8编码有可能会用一个字节,两个字节,三个字节去表示一个字符。
0xxxxxxxx 开头为0代表用一个字节表示,后面的xxxxxxx就是这个字符的表示位(码数在0000000~1111111,换成十进制就是0~127)
110xxxxx 10xxxxxx 代表用两个字节表示。(码数在127 ~ 11111111111,换成十进制就是127~2047)
1110xxxx 10xxxxxx 10xxxxxx 代表用三个字节表示(码数在2047 ~ 1111111111111111,换成十进制就是127~65535)
utf-16
utf16就比较好理解了,utf16全都是用两个字节来表示字符
js
js中用utf-16的编码格式来储存字符
btoa
btoa内部会先将参数中的每个字符进行码值的转换,如果转换得到的码值大于255,那么该函数就会报错
思路
base64编码
思路
因为btoa只支持一个字节表示的字符,
1、所以我们可以利用new TextEncoder().encode()接受一串字符串为输入,并且输出一个utf8编码的文本的unit8Array的数组,
2、我们可以再利用String.fromChatCode(...unit8Array的数组)可以得到数组中每个用一个字节表示的对应的unicode码,
3、这时候就可以把这个字符串给到btoa做base64的转换了。
代码
const str = '我是a';
const uint8_array = new TextEncoder().encode(str); // uint8Array [230, 136, 145, 230, 152, 175, 97]
const int_map_str = String.fromCharCode(...uint8_array); // 'æ\x88\x91æ\x98¯a'
const base64 = btoa(int_map_str); // 5oiR5pivYQ==
综上所述:'我是a' 的base64编码就是 '5oiR5pivYQ=='
代码解析
- new TextEncoder().encode(str)是如何得到 uint8Array [230, 136, 145, 230, 152, 175, 97]的呢?
1、‘我’的码值是:25105, 换成二进制就是:01100010 00010001 2、因为码值大于2047,所以在utf8编码中需要用三个字节表示,格式就是:1110xxxx 10xxxxxx 10xxxxxx,一共有10个x
3、将二进制:01100010 00010001,按照上面的格式补充,得到:11100110 10001000 10010001
4、将第三步得到的每8位二进制转换成10进制也就是:230 136 145 5、以此类推,将得到的数据都集合到一个数组中就可以得到 uint8Array [230, 136, 145, 230, 152, 175, 97]
base64解码
思路
按照上面编码的思路进行逆转
1、首先拿到了base64编码后的字符串'5oiR5pivYQ==',通过atob解码得到'æ\x88\x91æ\x98¯a'。
2、将得到的'æ\x88\x91æ\x98¯a',获取得到对应的uint8Array的字节流。
3、再将得到的uint8Array数组再作为参数传递给new TextDecoder().decode(),得到编码前的utf16字符串。
代码
const base64_str = '5oiR5pivYQ==';
const uint8_str = atob(base64_str); // 'æ\x88\x91æ\x98¯a'
const array = [...uint8_str].map(_v => _v.charCodeAt(0));
const uint8_array = new Uint8Array(array);
const source_str = new TextDecoder().decode(uint8_array);
代码解析
- new TextDecoder().decode(uint8_array)这一步如何知道是几个字节决定一个字符呢?
1、其实是通过 uint8Array [230, 136, 145, 230, 152, 175, 97]中得到的信息,数组的第一位是230, 2、之前说过utf8编码中,一个字节就可以表示的字符的码值会小于或等于127,两个字节表示的,那么数组的第一位会是大于 11000000 (十进制就是:192),三个字节表示的,那么数组第一位会大于 11100000 (十进制就是:224)
3、很明显,第一位是230,大于224,所以是3个字节表示的,也就是 230 136 145都是表示第一个字符的。
4、同理可得 230, 152, 175 是表示第二个字符的。
5、97 小于127,97自己就可以表示一个字符