鉴于 V 站聚聚每次都能支持错漏之处,以及补充我不懂的东西如 https://www.v2ex.com/t/531232#reply11 还有 https://www.v2ex.com/t/543304#reply30 所以这篇文章发上来虚心请教~
不知道 v 站支持 markdown 如何,先附上公众号地址,排版好看很多。
Base32
是一个 binary-to-text encoding schemes,顾名思义,就是将二进制数据转换为编码只有基础 32 个字符的数据编码方式,Base64
则是 64 个。注意编码不等同于加密,网上有误解 Base 编码方式为加密方式,实际上标准 Base64 编码解码无需额外信息即完全可逆。
一些协议如HTTP
, FTP (File Transfer Protocol)
[当指定发送文本时], SMTP (Simple Mail Transfer Protocol)
是text-based protocol,也就是只支持文本传输,不支持二进制传输。是的,http 上传文件,图片时使用的multipart/form-data
也是需要转成文本的。
所以附件如图片,文件等( binary )就可以用Base64
编码为 text 再传输。
如 data URI scheme定义了如下语法来识别网页中的资源:
data:[<media type>][;base64],<data>
HTML
中可以在标签中指定识别 Base64 编码
来展示资源,
<div>
<p>Taken from wikpedia</p>
<img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />
</div>
但因为Base64
是每 3 个原始字符编码成 4 个字符,不够时补=
(下文会详述),因此编码后的大小是有可能会比原文件大的,所以html
用 Base64
来展示图片而不是用具体的图片好处大概就只有少建立一条 http 连接以及少一个 http 请求(在 HTTP 1.1 以下),这种办法只有大量的小图片才有优越性了。
为了避免出现不符合规则的字符,方便把含有不可见字符串的信息用可见字符串表示出来。比如 http
协议当中的 headers 头部,必须进行 URLEncode
不然出现的等号可能使解析失败 空格也会使 http 请求解析出现问题,比如请求行也就是 request 就是以空格来划分的POST /hi/you HTTP/1
,值得注意的是 Base32
的字符列表里有不合法字符/
。
还有避免原始信息经过百花齐开的路由,网关多次转发,因有部分系统不支持此不可识别字符或将此作为控制符,将其转义、丢弃等,造成信息丢失,所以如电子邮件里的附件也是用 base64 编码的。
有 base64 编码的变种base64url,将 base64 编码中的+
换成-
以及将/
换成_
,甚至不需要往后面补=
了。这样子在 url 中传递东西时,不再需要 URL encode
,好处就是长度短了,以及好看了一点,毕竟%
有点视觉污染(实际上,还可以直接将编码后的东西存数据库了,因为base64
比 URLEncode
更通用了 )
RFC 向来都不会说明设计的历史由来,自然base64
编码也是一样,我参考的 rfc4648也只是说明了因为当时开发者们自己发明使用 base 64 并不规范,没有统一的标准,因此定义了一份通用标准。
然后呢,Base64
就是自己选了ASCII
子集( 64 个字符)为标准字符集,当然这也是因为 64 是 2 的 x 次方
(如 64 就是 2 的 6 次方),而 1 个 bit 分别有 0 和 1 两种状态,6 个 bit 也就是 2 的 6 次方=64 个状态,刚好可以表示 64 个字符,因此6 个 bit
就可以表达出 64 个字符了。就是下面定义的 64 个:
Table 1: The Base 64 Alphabet
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
The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters.
base64 处理
后的4
个标准字符集中的字符。值得注意的是,网上的示例或说明中,都或多或少有以下偏颇之处:
binary to text
的 binary=
,如按其他人的文章说的 8 位 8 位的转,根本不清楚要补多少=
When fewer than 24 input bits are available in an input group, bits with value zero are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character.
=
举一些例子来说明一下:
Input data: 0x14fb9c03d97e
16 进制: 1 4 f b 9 c | 0 3 d 9 7 e
2 进制: 00010100 11111011 10011100 | 00000011 11011001 01111110
6 位一组: 000101 001111 101110 011100 | 000000 111101 100101 111110
Decimal: 5 15 46 28 0 61 37 62
Output: F P u c A 9 l +
16 进制的0x14fb9c03d97e
作为输入,先转成二进制,然后 2 进制的每 24 位 选出来编码,上面例子就是:00010100 11111011 10011100
,然后 6 位一组的分开,得到000101 001111 101110 011100
。
然后分别转 10 进制,也就是000101
变成 5,001111
变成 15 等,再去 base64 定义的字符列表中找出此 10 进制对应的字符,以此类推,就是 base64 后的结果了。
上面例子是输入刚好是有 48 位,2 个 24 位,刚刚够,不需要补=
下面看看需要补=
的例子:
Input data: 0x14fb9c03
Hex: 1 4 f b 9 c | 0 3
8-bit: 00010100 11111011 10011100 | 00000011 开始补 0 =》 00000000 00000000
pad
6-bit: 000101 001111 101110 011100 | 000000 110000 000000 000000
Decimal: 5 15 46 28 0 48
pad with = =
Output: F P u c A w = =
注意上述输入只有 32 位,第一个 24 位处理完后,还剩下 8 位,因此需要补 16 个 0.
补完后,就是 48 位的输入了,照样每 24 位输出 4 个编码后的字符。
观察后半部分, 000000 110000 000000 000000
,第一个000000
因为后面还有内容,所以 10 进制为 0,因此编码字符为 A,这个很正常;而1100000
之后的两个 6 位0
,都是纯粹的填充(pading)了,因此并不用 A
而都用 =
代替掉**,注意不用A
**
说完 encode,decode 就容易啦,无非就是逆过程,RFC 都不屑于讲了。。。
一串 base64 后的字符串,根据每个字符在 base64 字符表里找到对应的 10 进制,然后转成 2 进制,最后多余补足的 000000 去掉,完了😰
URL_Encode
以及Unicode
相关留待下次说。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.