Base64

7 tools

什么是编码?

编码是将数据从一种表示形式转换为另一种的过程。在 Web 开发中,编码用于通过专为有限字符集设计的通道安全传输数据。

字符编码定义文本字符如何映射到字节。Base64 编码将二进制数据转换为 ASCII 文本。URL 编码使任意文本在 URL 中安全使用。

字符编码历史

字符编码是字符与其二进制表示之间的映射:

ASCII1963
128 字符

7 位美国标准代码。128 个字符:英文字母、数字、标点和控制码。

Latin-11987
256 字符

用于西欧语言的扩展 ASCII。添加了 128 个字符。不适合非拉丁文字。

Unicode1991
149 186+ 字符

覆盖全球所有书写系统的通用字符集。为超过 149,000 个字符定义代码点。

UTF-81993
全部 Unicode 字符

每字符使用 1-4 字节的可变宽度 Unicode 编码。兼容 ASCII。Web 上的主流编码,超过 98% 的网站使用。

UTF-161996
全部 Unicode 字符

每字符使用 2 或 4 字节的可变宽度编码。Windows、Java 和 JavaScript 字符串内部使用。

UTF-322000
全部 Unicode 字符

固定宽度编码:每字符始终 4 字节。Web 上很少见。

UTF-8 为何获胜

UTF-8 成为主流是因为它向后兼容 ASCII、自同步且对拉丁文本节省空间。任何 ASCII 文档都是有效的 UTF-8 文档,使迁移无缝进行。

Base64 编码

Base64 仅使用 64 个可打印的 ASCII 字符(A-Z、a-z、0-9、+、/)将二进制数据转换为文本表示。当二进制数据必须通过纯文本通道传输时,这是必要的。

工作原理

Base64 将输入字节分成 3 字节(24 位)块,将每块编码为 4 个 Base64 字符(每个 6 位)。如果输入不是 3 字节的倍数,则添加 = 填充字符:

输入十六进制字节Base64
"Man"77 61 6ETWFu
"Ma"4D 61TWE=
"M"4DTQ==

末尾的 = 填充字符表示完成最后一个 3 字节组还缺少几个字节。标准 Base64 始终生成长度为 4 的倍数的输出。

URL 编码

URL 只能包含一组有限的安全 ASCII 字符。任何超出该集合的字符在放入 URL 之前都必须进行百分号编码(URL 编码)。

百分号编码将每个不安全的字节替换为 % 加上表示该字节值的两个十六进制数字。

常见编码字符

字符编码后备注
Space%20最常见;在 application/x-www-form-urlencoded 表单提交中用 + 表示
&%26查询字符串分隔符;作为字面值使用时必须编码
=%3D查询字符串中的键值分隔符;作为数据使用时编码
+%2B在 application/x-www-form-urlencoded 中解释为空格;编码以保留字面 +
#%23片段标识符;在路径或查询中作为字面数据使用时编码
/%2F路径段分隔符;作为字面数据而非路径分隔符时编码
:%3AScheme 分隔符;在路径和查询上下文中编码
@%40用于 mailto: 和 auth;作为字面数据使用时编码

encodeURI 与 encodeURIComponent

JavaScript 提供两个范围不同的编码函数。encodeURI 编码完整 URL(保留 URL 结构字符)。encodeURIComponent 编码 URL 组件——编码除 A-Z、a-z、0-9、-、_、.、~ 之外的所有字符。

Web 开发中编码的应用场景

HTTP 基本认证

Authorization: Basic 头以 Base64(用户名:密码) 编码凭据。这是传输便利性编码,不是安全措施。始终将 HTTPS 与 Basic Auth 一起使用。

Data URI

Data URI 将文件内容直接嵌入 HTML 或 CSS:data:image/png;base64,....。内联编码图片和字体消除了 HTTP 请求,但增加了文档大小。

MIME 电子邮件附件

电子邮件为 7 位 ASCII 而设计。MIME 在传输前将二进制附件(图片、PDF)进行 Base64 编码。

JWT Token

JWT Token 对所有三个部分使用 Base64url 编码,使 token 对 URL 安全无需额外的百分号编码。

查询字符串参数

URL 查询字符串中的任何用户提供的数据都必须进行百分号编码。

国际化域名

非 ASCII 域名(如 münchen.de)使用 Punycode(xn-- 前缀)编码,以兼容 DNS 系统。

常见问题

Base64 是一种加密形式吗?

不是。Base64 是编码,不是加密。它是没有密钥的可逆变换。永远不要将 Base64 用作安全措施。

为什么 Base64 输出有时以 == 结尾?

Base64 以 3 字节为一组处理输入。如果输入不是 3 的倍数,则添加 = 填充。

Base64 和 Base64url 有什么区别?

Base64url 是 URL 安全的变体,将 + 替换为 -,将 / 替换为 _,通常省略 = 填充。JWT 使用 Base64url。

何时使用 encodeURI 而非 encodeURIComponent?

对单个值使用 encodeURIComponent。对要保留 URL 结构字符的完整 URL 字符串使用 encodeURI。

为什么 UTF-8 比 UTF-16 更适合 Web?

UTF-8 与 ASCII 兼容,对拉丁文本节省空间。HTTP 和 HTML 默认使用 UTF-8。

什么是百分号编码?

百分号编码将字符表示为 % 加两位十六进制字节值。例如,空格是 %20。

编码会影响性能吗?

Base64 使数据大小增加约 33% 并增加 CPU 开销。URL 编码的开销很小。

什么是 Punycode?

Punycode 是在 ASCII 兼容的 DNS 系统中表示 Unicode 字符的编码。如 münchen.de 在 DNS 查询中编码为 xn--mnchen-3ya.de。