是什么
- Base64将每3个二进制字节编码为4个ASCII字符。
- Base64使用以下字符进行编码:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
。 - 如果输入字节数不为3的整数倍,Base64在输出字符串末尾使用字符
=
补全(padding),使输出字符串长度为4的整数倍。 - Base64属于定长编码。只要输入字节数不变,Base64编码输出的字符数就不变。Base62、Base58不属于定长编码。
变种
Base64 URL Safe
Base64输出包含+
和/
两个特殊字符,在URL中可能引起问题。
Base64 URL Safe将+/
替换为-_
,以避免上述问题。
Base62
在Base64基础上,去掉+
和/
两个特殊字符,仅保留数字、字母大小写。
Base58
在Base62基础上,去掉0
(数字0)、I
(大写字母 i)、O
(大写字母 o) 和 l
(小写字母 L),方便人阅读,避免歧义。
实现
Python
编码Base64:
>>> import base64
>>> input_string = 'Base64输出包含+和/两个特殊字符'
>>> input_string_bytes = input_string.encode('utf-8')
>>> print(input_string_bytes)
b'Base64\xe8\xbe\x93\xe5\x87\xba\xe5\x8c\x85\xe5\x90\xab+\xe5\x92\x8c/\xe4\xb8\xa4\xe4\xb8\xaa\xe7\x89\xb9\xe6\xae\x8a\xe5\xad\x97\xe7\xac\xa6'
>>> base64.standard_b64encode(input_string_bytes) # 标准Base64编码
b'QmFzZTY06L6T5Ye65YyF5ZCrK+WSjC/kuKTkuKrnibnmrorlrZfnrKY='
>>> base64.urlsafe_b64encode(input_string_bytes) # Base64 URL Safe编码
b'QmFzZTY06L6T5Ye65YyF5ZCrK-WSjC_kuKTkuKrnibnmrorlrZfnrKY='
需要区分两种“编码”:
- UTF-8将Unicode字符串“编码”为二进制数据;
- Base64将二进制数据“编码”为ASCII字符串。
传统字符编码(例如UTF-8)将各种字符(特别是汉字等非ASCII字符)转换为二进制数据,以便于计算机本地存储;Base64属于二进制到文本编码,这类编码的目标是在Email、HTML等纯文本格式里表示二进制数据,因此将二进制数据转换为ASCII字符串。
既然Base64将二进制字节编码为ASCII字符,为什么b64encode返回bytes对象?原因主要有两点:一是避免重复来回转换,二是遵守“‘编码’是将字符串转换为二进制”的范式。
解码Base64:
>>> import base64
>>> input_string = 'QmFzZTY06L6T5Ye65YyF5ZCrK+WSjC/kuKTkuKrnibnmrorlrZfnrKY='
>>> base64.standard_b64decode(input_string)
b'Base64\xe8\xbe\x93\xe5\x87\xba\xe5\x8c\x85\xe5\x90\xab+\xe5\x92\x8c/\xe4\xb8\xa4\xe4\xb8\xaa\xe7\x89\xb9\xe6\xae\x8a\xe5\xad\x97\xe7\xac\xa6'
>>> base64.standard_b64decode(input_string).decode('utf-8')
'Base64输出包含+和/两个特殊字符'
Java
编码Base64:
@Test
public void base64EncodeTest() {
String inputString = "Base64输出包含+和/两个特殊字符";
byte[] inputStringBytes = inputString.getBytes(StandardCharsets.UTF_8);
System.out.println(new String(Base64.getEncoder().encode(inputStringBytes), StandardCharsets.US_ASCII));
// 打印"QmFzZTY06L6T5Ye65YyF5ZCrK+WSjC/kuKTkuKrnibnmrorlrZfnrKY="
}
解码Base64:
@Test
public void base64DecodeTest() {
String inputString = "QmFzZTY06L6T5Ye65YyF5ZCrK+WSjC/kuKTkuKrnibnmrorlrZfnrKY=";
System.out.println(new String(Base64.getDecoder().decode(inputString), StandardCharsets.UTF_8));
// 打印“Base64输出包含+和/两个特殊字符”
}
解码Base64时,Python和Java都同时支持入参为字符串或字节数组。可能是因为Base64字符串总是可以使用ASCII实现字符编码,因此实现了两个重载方法。Java的byte[] decode(String src)
重载方法是对byte[] decode(byte[] src)
的封装,内部也是将入参src
先用字符编码ISO_8859_1(兼容ASCII)转换为字节数组。
编码Base64 URL Safe:
@Test
public void base64UrlSafeEncodeTest() {
String inputString = "Base64输出包含+和/两个特殊字符";
byte[] inputStringBytes = inputString.getBytes(StandardCharsets.UTF_8);
System.out.println(new String(Base64.getUrlEncoder().encode(inputStringBytes), StandardCharsets.US_ASCII));
// 打印"QmFzZTY06L6T5Ye65YyF5ZCrK-WSjC_kuKTkuKrnibnmrorlrZfnrKY="
}
编解码Base62:https://github.com/seruco/base62
参考资料
https://developer.mozilla.org/en-US/docs/Glossary/Base64
https://en.wikipedia.org/wiki/Base62
https://docs.python.org/3/library/base64.html
https://docs.oracle.com/javase/8/docs/api/java/util/Base64.html