Base64
所谓Base64,就是说从ASCII码中选出64个字符—-大写字母A-Z、小写字母a-z、数字0-9、符号”+”、”/”(再加上作为填充字符的”=”,实际上是65个字符),作为一个基本字符集。然后,其他所有符号都转换成这个字符集中的字符。
具体来说,转换方式可以分为四步:
- 将每3个字节作为一组,一共是24个二进制位: 3x8=24
- 将这24个二进制位分为4组,每个组有6个二进制位: 24/4=6
- 在每组前面加两个00,扩展成32个二进制位,即3个字节: 4x(6+2)=32
- 根据下表,得到扩展后的每个字节的对应符号,这就是Base64的编码值
说明
- 因为转换后的每个字符的最高两位都是0,所以实际有效位数是6位,也就是2^6=64个字符就可以覆盖所有的编码。
- 如果剩下的字符不足3个字节,则用0填充,输出字符使用’=’,因此编码后输出的文本末尾可能会出现1或2个”=”。
- 因为Base64将3个字节转化成4个字节,因此Base64编码后的文本,会比原文本大出三分之一左右。
标准的Base64编码表如下:
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
可以看到其实还是蛮有规律的,就是大写字母A-Z、小写字母a-z、数字0-9、符号”+”、”/”一共64个字符,编号(码值)从0到63,还有一个用于填充的’=’。
Padding
Base64是三个字节(Bytes)作为一组(24-bit block)的编码转换,如果字节数不是三的倍数,那么就会出最后一组只有一个或者两个字节的情况,那么讲会做这样的处理:
- 一个字节的情况:将这一个字节的8个二进制位,按照上面的规则转成二组,最后一组除了前面加二个0以外,后面再加4个0。这样得到一个二位的Base64编码,再在末尾补上两个”=”号。 比如,”M”这个字母是一个字节,二进制是01001101,可以转化为二组00010011、00010000,对应的Base64值分别为T、Q,再补上二个”=”号,因此”M”的Base64编码就是TQ==。
- 二个字节的情况:将这二个字节的一共16个二进制位,按照上面的规则,转成三组,最后一组除了前面加两个0以外,后面也要加两个0。这样得到一个三位的Base64编码,再在末尾补上一个”=”号。 比如,”Ma”这个字符串是两个字节,二进制表示是01001101 01100001,可以转化成三组00010011、00010110、00000100以后,对应Base64值分别为T、W、E,再补上一个”=”号,因此”Ma”的Base64编码就是TWE=。
TIPS
后缀的’=’用于表示最后一组缺失的字节数。’==’表示最后一组只包含一个字节,’=’表示最后一组包含两个字节。
Base64的应用
标准的Base64并不适合直接放在URL里传输,根据网络标准RFC1738的规定:only alphanumerics, the special characters “$-_.+!*’(),”, and reserved characters used for their reserved purposes may be used unencoded within a URL.
RFC 1738 Uniform Resource Locators (URL) December 1994
alpha = lowalpha | hialpha
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
"8" | "9"
safe = "$" | "-" | "_" | "." | "+"
extra = "!" | "*" | "'" | "(" | ")" | ","
national = "{" | "}" | "|" | "\" | "^" | "~" | "[" | "]" | "`"
punctuation = "<" | ">" | "#" | "%" | <">
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "="
hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
"a" | "b" | "c" | "d" | "e" | "f"
escape = "%" hex hex
unreserved = alpha | digit | safe | extra
uchar = unreserved | escape
xchar = unreserved | reserved | escape
digits = 1*digit
NOTES
因为”%”用于URL转义,所以它本身被URL编码为”%25”。
下面是常见的URL保留字以及相应的编码:
! # $ & ' ( ) * + , / : ; = ? @ [ ]
%21 %23 %24 %26 %27 %28 %29 %2A %2B %2C %2F %3A %3B %3D %3F %40 %5B %5D
回到正题,因为’/’和’=’是URI的保留字符,对于URL有特殊的意义。所以标准的做法就是对Base64编码过的URL进行 URL encoding ——(’+’ => ‘%2B’, ‘/’ => ‘%2F’,’=’ => ‘%3D’),但是这样子会导致URL无意义的变长,而且多了一个URL编解码步骤。为了避免这个问题,出现了一种用于URL的改进Base64编码变种,它其实就是简单的把标准Base64中的’+’和’/’分别改成了’-‘和’_‘。对于填充字符’=’,有些变种是把它直接去掉,有些则是把它替换成’.’。