Base64 编解码详解:原理、用途与实践

Base64 是一种将二进制数据编码为 ASCII 文本的编码方案。它在网络传输、数据嵌入和安全令牌中被广泛使用。本文将从算法原理到编程实践,带你全面了解 Base64。

Base64 编码原理

Base64 的核心思想是将每 3 个字节(24 位)的二进制数据拆分为 4 组 6 位数据,然后通过查表映射为可打印的 ASCII 字符。

编码步骤

  1. 将输入的每个字符转换为 8 位二进制
  2. 将所有二进制位连起来,按每 6 位一组分割
  3. 将每组 6 位转换为十进制数(0-63)
  4. 用字符表映射为对应字符

标准 Base64 字符表包含 64 个字符:

A-Z  (索引 0-25)
a-z  (索引 26-51)
0-9  (索引 52-61)
+    (索引 62)
/    (索引 63)
=    (填充字符)

编码示例

以字符串 Hi! 为例:

字符:  H         i         !
ASCII: 72        105       33
二进制:01001000  01101001  00100001

按 6 位分组:
010010  000110  100100  100001

十进制: 18      6       36      33
Base64:  S      G       k      h

结果:"Hi!" → "SGkh"

填充规则

当输入字节数不是 3 的倍数时,需要在末尾补零并用 = 填充:

  • 余 1 字节:补 4 个零位,输出 2 个 Base64 字符 + ==
  • 余 2 字节:补 2 个零位,输出 3 个 Base64 字符 + =
"A"  → "QQ=="   (1 字节 → 补 2 个 =)
"AB" → "QUI="   (2 字节 → 补 1 个 =)
"ABC"→ "QUJD"   (3 字节 → 无填充)
💡 提示:Base64 编码后的数据体积约为原始数据的 4/3 倍(约增加 33%)。这是因为每 3 字节变成了 4 个字符。

Base64 的常见变体

除了标准 Base64,还有几种常用变体:

  • URL 安全 Base64:使用 - 替换 +_ 替换 /,避免 URL 中的特殊字符冲突
  • 无填充 Base64:省略末尾的 =,常见于 JWT
  • MIME Base64:每 76 个字符插入换行(用于邮件传输)

Base64 应用场景

1. 图片内嵌(Data URI)

将小图片编码为 Base64,直接嵌入 HTML 或 CSS,减少 HTTP 请求:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhE..." />

/* CSS 中使用 */
.icon {
  background-image: url(data:image/svg+xml;base64,PHN2Zy...);
}
⚠️ 注意:不建议将大于 5KB 的图片转为 Base64 内嵌。大图片会增加 HTML 体积,且无法被浏览器独立缓存。

2. JWT 令牌

JWT 的 Header 和 Payload 部分使用 URL 安全的 Base64 编码(无填充)。详见 JWT 完全指南

// JWT 结构示例
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U
 ↑ Header (Base64)     ↑ Payload (Base64)         ↑ Signature

3. 邮件附件(MIME)

电子邮件的 SMTP 协议只能传输 ASCII 文本,所以附件的二进制数据必须经过 Base64 编码。

4. API 数据传输

在 JSON API 中传输二进制数据(如文件上传、加密结果)时,常用 Base64 编码为字符串:

{
  "filename": "report.pdf",
  "content": "JVBERi0xLjQKMSAwIG9iago8PAov...",
  "encoding": "base64"
}

各语言编程实践

JavaScript

// 浏览器环境
const encoded = btoa("Hello, World!");
// "SGVsbG8sIFdvcmxkIQ=="

const decoded = atob("SGVsbG8sIFdvcmxkIQ==");
// "Hello, World!"

// 处理 UTF-8 中文
function b64EncodeUnicode(str) {
  return btoa(encodeURIComponent(str).replace(
    /%([0-9A-F]{2})/g,
    (_, p1) => String.fromCharCode('0x' + p1)
  ));
}

// Node.js
const buf = Buffer.from("Hello", "utf-8");
const b64 = buf.toString("base64"); // "SGVsbG8="

Python

import base64

# 编码
encoded = base64.b64encode(b"Hello, World!")
print(encoded)  # b'SGVsbG8sIFdvcmxkIQ=='

# 解码
decoded = base64.b64decode(b"SGVsbG8sIFdvcmxkIQ==")
print(decoded)  # b'Hello, World!'

# URL 安全编码
url_safe = base64.urlsafe_b64encode(b"Hello?World!")
print(url_safe)  # b'SGVsbG8_V29ybGQh'
💡 安全提示:Base64 是编码(encoding),不是加密(encryption)。任何人都能解码 Base64 数据。绝不要用 Base64 来"隐藏"敏感信息,如密码或密钥。如需安全传输,请使用 加密哈希 或 AES 等真正的加密算法。

🛠️ 在线 Base64 编解码工具

打开 Base64 工具 →

延伸阅读