Base64编码中为什么会有等号(=)
如果对字符串"ab"进行Base64编码,得到的结果将是:YWI=,结果中为什么会出现=呢,这就需要了解一下base64编码背后的原理。
Base64是一种便于网络传输的字节码编码方式,之所以叫Base64是由于它的编码结果是由64个可打印字符组成,这些字符在不同系统间是通用的。
64个字符如下表所示
索引
|
对应字符
|
索引
|
对应字符
|
索引
|
对应字符
|
索引
|
对应字符
|
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
|
|
|
15
|
P
|
32
|
g
|
49
|
x
|
|
|
16
|
Q
|
33
|
h
|
50
|
y
|
|
|
大家可以看到这里面并没 '=' 这个字符,这是因为 ’=‘ 其实是填充字符。
如果需要表示上面的64个字符,那么需要6bit,也就是2^6=64,base64的核心思想就是,将3个
字节拆分成4个6bit,然后对每个6bit的高位补2个0,构成1个字节。也即是每3个字节最终结果将变成4个字节。
如果原始字符串的字节数不是3的整数倍,那么就用0来填充,用来填充的0就被编码成了'=',这就是出现=的原因,并且只会出现在结果出,如果原始字符刚好是3字节的整数倍,那么就没有等号了。
回到开头的例子,我们看下ab是如何计算得到YWI=的。
- 1、ab对应的ascaii编码的二进制表示为:011000001 01100010
- 2、由于只有两个字节,需要填充到3个字段,也就是:011000001 01100010 00000000
- 3、拆分成四个6bit:011000 010110 001000 000000
- 4、高位补两个0,变成四字节:00011000 00010110 00001000 00000000
- 5、按照上表的对应关系:24-Y 22-W 8-I 填充-=, 也即是YWI=。
需要注意填充的0是要被转化成=,而不是上表中的A。
顺便附上golang示例代码
1
2
3
4
5
6
7
8
9
|
func main() {
str := "ab"
// base64编码
encodedStr := base64.URLEncoding.EncodeToString([]byte(str))
fmt.Println(encodedStr) // YWI=
// base64解码
decodeStr, _ := base64.URLEncoding.DecodeString(encodedStr)
fmt.Println(string(decodeStr)) // ab
}
|
如果不希望保留填充的=,可以在编码后去掉,解码前填充上
示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
func main(){
str := "ab"
// base64编码
encodedStr := base64.URLEncoding.EncodeToString([]byte(str))
encodedStr = strings.TrimRight(encodedStr, "=") // 去掉填充的=
fmt.Println(encodedStr) // YWI
// 解码时,长度不是4的倍数,需要用=填充
i := len(encodedStr) % 4
if i != 0 {
encodedStr += strings.Repeat("=", 4-i)
}
// base64解码
decodeStr, _ := base64.URLEncoding.DecodeString(encodedStr)
fmt.Println(string(decodeStr)) // ab
|
|