URL 编码与 Base64 编码:有什么区别?
URL 编码(百分号编码)依据 RFC 3986 将 URL 中的特殊字符转换为 %XX 格式。Base64 编码依据 RFC 4648 使用 64 个 ASCII 字符将二进制数据转换为文本字符串。二者用途不同,不能相互替代。
什么是 URL 编码?
URL 编码,也称为百分号编码,由 RFC 3986 定义,是一种用于表示 URI 中不被允许或具有特殊含义的字符的机制。每个需要编码的字符会被转换为一个或多个字节(使用 UTF-8),而每个字节则表示为一个百分号(%)后跟两位大写十六进制数字。
例如,空格字符会变成 %20,&符号会变成 %26,而像欧元符号这样的非 ASCII 字符则会变成 %E2%82%AC(三个 UTF-8 字节,每个都经过百分号编码)。
// JavaScript 中的 URL 编码示例
encodeURIComponent('hello world'); // "hello%20world"
encodeURIComponent('price=10&qty=2'); // "price%3D10%26qty%3D2"
encodeURIComponent('cafe'); // "caf%C3%A9"
URL 编码专门用于确保 URL 安全且有效。它只对 URI 中不被允许或具有保留含义的字符进行编码,而字母数字字符以及少数几个安全符号则保持不变。
什么是 Base64 编码?
Base64 编码由 RFC 4648 定义,是一种二进制到文本的编码方案,它使用一组 64 个 ASCII 字符来表示二进制数据:A-Z、a-z、0-9、+ 和 /,并用 = 进行填充。每三个字节的输入会产生四个字符的输出。
Base64 的设计初衷是在那些只能可靠支持文本的通道上传输二进制数据,例如电子邮件(MIME),或将数据嵌入 XML/JSON 中。它并非专门针对 URL,并且会对所有输入字节进行编码,而不仅仅是特殊字符。
// JavaScript 中的 Base64 编码示例
btoa('hello world'); // "aGVsbG8gd29ybGQ="
btoa('price=10&qty=2'); // "cHJpY2U9MTAmcXR5PTI="
// 对于 Unicode 字符串,需先编码为 UTF-8
function toBase64(str) {
return btoa(unescape(encodeURIComponent(str)));
}
toBase64('cafe'); // "Y2Fmw6k="
此外还有一种 URL 安全的 Base64 变体(Base64url),它将 + 替换为 -,将 / 替换为 _,并且通常省略 = 填充。这种变体用于 JWT、URL 中的 data URI 以及其他标准 Base64 字符会与 URL 语法冲突的场景。
主要区别
| 特性 | URL 编码 | Base64 编码 |
|---|---|---|
| 标准 | RFC 3986 | RFC 4648 |
| 用途 | 使 URL 安全 | 以文本表示二进制 |
| 编码对象 | 仅特殊/保留字符 | 所有输入字节 |
| 输出格式 | %XX 十六进制序列 |
A-Z、a-z、0-9、+、/、= |
| 体积增长 | 可变(仅被编码的字符增长) | 始终增大约 33% |
| 可逆 | 是 | 是 |
| 人类可读 | 部分可读(非保留字符保持不变) | 否 |
| 默认 URL 安全 | 是(设计使然) | 否(包含 +、/、=) |
何时使用哪种编码
使用 URL 编码,当你需要在 URL 中包含特殊字符时,例如查询参数值、路径段或片段标识符。对于任何数据必须嵌入 URL 结构的情况,URL 编码都是正确的选择。
使用 Base64 编码,当你需要将二进制数据(图片、文件、加密载荷)表示为文本、在 JSON 或 XML 中嵌入二进制内容,或通过纯文本通道传输数据时。Base64 还用于 HTTP 基本认证(Basic Authentication)头部和 JSON Web Token(JWT)。
// URL 编码:将搜索词嵌入 URL
const searchUrl = 'https://example.com/search?q=' +
encodeURIComponent('C++ & Java');
// "https://example.com/search?q=C%2B%2B%20%26%20Java"
// Base64:在 CSS 或 HTML 中嵌入图片
const imageData = 'data:image/png;base64,iVBORw0KGgoAAAANS...';
// Base64:HTTP 基本认证头部
const credentials = btoa('username:password');
const header = 'Authorization: Basic ' + credentials;
可以将二者结合使用吗?
可以,而且在某些情况下必须结合使用。如果你需要将 Base64 编码的数据作为 URL 参数传递,标准的 Base64 输出可能包含 +、/ 和 = 字符,而这些字符在 URL 中具有特殊含义。你有两种选择:
方案一: 在将 Base64 字符串放入 URL 之前先对其进行 URL 编码。+ 会变成 %2B,/ 会变成 %2F,= 会变成 %3D。
方案二: 使用 Base64url 变体(RFC 4648 第 5 节),它将 + 替换为 -,将 / 替换为 _,并移除填充。这正是 JWT 和许多现代 API 所采用的方法。
// 方案一:对标准 Base64 进行 URL 编码
const base64 = btoa('binary data here'); // "YmluYXJ5IGRhdGEgaGVyZQ=="
const urlSafe = encodeURIComponent(base64);
// "YmluYXJ5IGRhdGEgaGVyZQ%3D%3D"
// 方案二:Base64url 编码
function toBase64url(str) {
return btoa(str)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
}
toBase64url('binary data here');
// "YmluYXJ5IGRhdGEgaGVyZQ"