1. 前言
Base64 是网络中存储和传输的二进制数据的普遍用法。楼主最开始接触到Base64编码和解码是想要通过URL查询参数传送一串JSON字符串,而又不想被人明显看出来是一串JSON字符串,于是想做简单的转码。一下就找到了挂在window对象下的btoa和atob函数,但是,btoa和atob无法编解码中文,就增加了另外两个函数encodeURIComponent和decodeURIComponent(encodeURI和decodeURI也可)。编码过程:JSON字符串 → encodeURIComponent → btoa → Base64字符串,解码过程:Base64字符串 → atob → decodeURIComponent → JSON字符串。那有没有更直接的方式呢?
当然是有的,后面就找到了crypto-js。crypto-js还是不错的JS工具库,支持AES、SHA256、SHA512、SHA384、Base64、MD5等等,基本该有的都有了,唯一遗憾是还没有支持RSA。想了解crypto-js的同学,参见crypto-js - npm和crypto-js源码。那是不是自己也可以实现crypto-js这样的库?当然也是可以的,需要补充一下相应转码的知识,以及一些二进制的运算。JavaScript的二进制运算符参见我的这一篇文章的前言部分,进行快速预览。
言归正传,基于个人兴趣和对二进制数据处理的好奇,自己实现了Base64的编码和解码函数。那么Base64到底是什么呢?直白点说,就是用64个(2^6=64)ASCII字符来表示所有信息,将数据的每3个字节为一组(24bits),拆解成4个6bits,各个6bits高位补2个0,得到4个字节,每个字节取值范围是0b00000000~0b00111111(0~63),用64个ASCII字符来对应。基本原理就是这样,至于剩下1个或2个字节不成一组的问题,会使用=字符填充。
2. Base64字符查询表
Base64是选取A~Z、a~z、0~9、+和/这64个ASCII字符作为映射,编码映射表如下所示,数组索引index为编码值,每个编码值映射1个ASCII字符。最后一个=是当字节数量不够时用来填充的,本处为了方便也放到了编码表中。
// Base64编码表,使用2^6=64个字符来编码
const dictionary = [
'A', // 0b000000 <-> A
'B', // 0b000001 <-> B
'C', // 0b000010 <-> C
'D', // 0b000011 <-> D
'E', // 0b000100 <-> E
'F', // 0b000101 <-> F
'G', // 0b000110 <-> G
'H', // 0b000111 <-> H
'I', // 0b001000 <-> I
'J', // 0b001001 <-> J
'K', // 0b001010 <-> K
'L', // 0b001011 <-> L
'M', // 0b001100 <-> M
'N', // 0b001101 <-> N
'O', // 0b001110 <-> O
'P', // 0b001111 <-> P
'Q', // 0b010000 <-> Q
'R', // 0b010001 <-> R
'S', // 0b010010 <-> S
'T', // 0b010011 <-> T
'U', // 0b010100 <-> U
'V', // 0b010101 <-> V
'W', // 0b010110 <-> W
'X', // 0b010111 <-> X
'Y', // 0b011000 <-> Y
'Z', // 0b011001 <-> Z
'a', // 0b011010 <-> a
'b', // 0b011011 <-> b
'c', // 0b011100 <-> c
'd', // 0b011101 <-> d
'e', // 0b011110 <-> e
'f', // 0b011111 <-> f
'g', // 0b100000 <-> g
'h', // 0b100001 <-> h
'i', // 0b100010 <-> i
'j', // 0b100011 <-> j
'k', // 0b100100 <-> k
'l', // 0b100101 <-> l
'm', // 0b100110 <-> m
'n', // 0b100111 <-> n
'o', // 0b101000 <-> o
'p', // 0b101001 <-> p
'q', // 0b101010 <-> q
'r', // 0b101011 <-> r
's', // 0b101100 <-> s
't', // 0b101101 <-> t
'u', // 0b101110 <-> u
'v', // 0b101111 <-> v
'w', // 0b110000 <-> w
'x', // 0b110001 <-> x
'y', // 0b110010 <-> y
'z', // 0b110011 <-> z
&