Base64 编码

◇ Base64 是个二进制转文本的编码方案,它将每 3 个 8bit 数据表示为 4 个使用 6bit 编码的 Base64 字符。
◇ Base64 是 Base 编码的一种,其他 Base 编码如:Base16、Base32,”Base”后的数字越小,用来编码的字符数量越少。
◇ Base 编码的使用场景是在某些仅支持文本(甚至仅支持有限数量的文本字符)的环境中存储或传输数据。
◇ Base 编码规则详细定义在RFC4648
◇ Base64 编码的 6 个 bit 位,二进制值从 000000 到 111111 分别编码为字符“A-Z”,“a-z”,“0-9”,“+”,“/” 。另外有个 padding 字符“=”,当末尾 bit 组长度不够 24bit 的时候,用一个或两个“=”标识编码前缺少几个 8bit 才够 24bit,从而在解码时能正确解码“=”前的那个字符。
◇ 综上可得 Base64 编码结果有如下特性:
(0)Base64 编码结果中最多有 65 种字符。
(1)“=”字符只可能出现在编码结果末尾,数量不会超过两个。
(2)编码结果的字符数量是 4 的倍数。
(3)编码后的结果字符如果使用 ASCII 编码存储或展示,由于每个 ASCII 字符占用 8bit 空间,也就是用每 8bit 存储原来数据的 6bit,所以占用存储空间大约是原数据的 8/6=4/3 倍。

Base64 示例

示例 1

☆ 待编码数据是用 ASCII 编码的“Man”对应的二进制数据

● 编码前数据的二进制内容如下图。

● 将每 24bit 分成 6bit 组,每个 6bit 组使用 Base64 字符表示如下,可得“TWFu”。

示例 2

☆ 待编码数据是用 ASCII 编码的“Mana”对应的二进制数据

● 编码前二进制数据是示例 1 二进制内容后接“01100001”。
● 将每 24bit 分成 6bit 组,第 1 个 24bit 组与示例 1 一致。第 2 个 24bit 组中第 1 个 6bit 组是“011000”对应字符“Y”,第 2 个 6bit 组是“01”末尾填充 0 得到“010000”对应字符“Q”。由于第 2 个 24bit 组只有 8bit,还差两个 8bit 才够 24bit,所以使用两个 padding 字符标识。最终编码就是“TWFuYQ==”。

JS 中的 Base64 编码

○ JS 提供了btoa()函数用于将二进制字符串转为 Base64 字符串。例如调用 btoa(“Mana”)可得到”TWFuYQ==”,即上述示例 2 的结果。另外有 atob()函数执行相反操作。
○ btoa() 函数将输入字符串中每个字符当做 1 字节二进制数据处理,如果输入字符串中包含有效长度超过 1 字节的字符,就会报异常错误。
○ JS 的字符是通过 UTF-16 编码的,每个字符占 2 字节空间,其中的 ASCII 字符虽然也占 2 字节,但仅第 1 个字节内是有效内容,第二个字节全零,所以 btoa()处理 ASCII 字符不会报异常。
○ 可以通过以下表达式取值长度是否大于 2 判断某字符有效长度是否超过 1 字节。

1
<string>.charCodeAt(0).toString(16)

DataUrl

♂ Base64 编码的一个应用场景是在 HTML 或 CSS 文件中内嵌图片、SourceMap 等二进制资源,内嵌通过 DataUrl 实现。
♂ DataUrl 是种特殊的 url,它将数据内容直接嵌入在 url 里而不需要额外的外部文件。它以”data:”开头,包含如下 4 个部分。

1
data:[<mediatype>][;base64],<data>

♂ 其中 <mediatype> 是一个 MIME 类型字符串,标识 data 内容的格式,取值如“image/jpeg”,“application/x-www-form-urlencoded”,如果省略则按照“text/plain;charset=US-ASCII”处理。
♂ 当有“;base64”时表示 data 是经过 Base64 编码的。

DataUrl 示例

示例 1

☆ webpack 的 devtool 配置项

■ devtool 配置项的“inline-”和“eval-”两个前缀的含义是将 SourceMap 嵌入在打包文件中。
■ “inline-”方式,以“inline-source-map”为例,每个 bundle 对应一个 SourceMap,附加到整个 bundle 文件的末尾。
■ “eval-”方式,以“eval-source-map”为例,每个模块对应一个 SourceMap,附加到每个模块 eval 包裹内部的末尾。此种情况下,二次编译时能做到模块级 SourceMap 的单独替换,因此在 webpack dev rebuild 时更有速度优势。

示例 2

☆ webpack 的 url-loader

■ url-loader 的 “options” 提供了一个 “limit” 配置项,当文件大于这个配置项值时执行 file-loader 的行为,否则便将资源转换成 DataUrl 嵌入到引入位置。
■ url-loader 和 file-loader 自 webpack5 起被“module.rules.type”配置项替代。

示例 3

☆ 占用空间最小的 base64 图片的 DataUrl

■ web 页面中有时需要一个有效的 元素占位,通常将其 src 属性设置为如下 DataUrl 内容。

1
data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==

■ 这个字符串中的 Base64 编码内容是一个 1x1 像素的透明 GIF 图片的数据。

参考文献

Base64 wiki
MDN Data URLs
webpack devtool