Base64 是什么
Base64 是一种将任意二进制数据编码为纯 ASCII 字符串的方案。它选用 64 个可打印字符(A-Z、a-z、0-9、+、/)来表示数据,外加 = 作为填充符。因为输出只包含 ASCII 字符,Base64 编码后的数据可以安全地穿过只支持文本的通道——这是它最核心的价值。
为什么需要 Base64
许多早期协议(SMTP 邮件、HTTP 头部、JSON 文本)只能传输可打印 ASCII 字符。如果你要在一个 JSON 字段里传递一张 PNG 图片的二进制数据,直接嵌入会包含大量不可打印字节,导致解析失败。Base64 把这些二进制字节"翻译"成安全文本,解决了这个传输问题。
编码原理详解
核心算法
Base64 将输入数据按每 3 字节(24 bit)一组处理:
- 取 3 字节二进制数据,共 24 bit
- 将 24 bit 拆分为 4 组,每组 6 bit
- 每个 6 bit 值(范围 0-63)映射到 Base64 字符表中的一个字符
- 若最后一组不足 3 字节,用
=填充至 4 字符
字符映射表
索引 字符 索引 字符 索引 字符
0-25 A-Z 26-51 a-z 52-61 0-9
62 + 63 / 填充 =
编码示例
编码字符串 Man:
| 步骤 | 值 |
|---|---|
| ASCII | M=77, a=97, n=110 |
| 二进制 | 01001101 01100001 01101110 |
| 6 bit 分组 | 010011 010110 000101 101110 |
| 十进制 | 19, 22, 5, 46 |
| Base64 | TWFu |
膨胀率
3 字节输入编码为 4 字符输出,膨胀率恒为 4/3 ≈ 33.3%。对于不足 3 字节的输入,膨胀率更高:1 字节输入编码为 4 字符(含 2 个 =),膨胀率 300%。
变体:URL-Safe Base64
标准 Base64 中的 + 和 / 在 URL 中有特殊含义,会导致解析歧义。RFC 4648 §5 定义了 URL-safe 变体:
+→-/→_- 通常省略末尾
=填充
JWT、Data URL 等场景默认使用 URL-safe 变体。
实际应用场景
1. Data URL(内联资源)
在 HTML/CSS 中直接嵌入小图片,避免额外 HTTP 请求:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..." alt="logo">
适用条件:小于 4KB 的资源。大图片用 Base64 会导致 HTML 体积膨胀且阻塞解析。
2. 邮件附件(MIME)
SMTP 协议最初只支持 7-bit ASCII 文本。MIME 标准使用 Base64 将二进制附件编码为文本,使图片、PDF 等可以通过邮件传输。每 76 个字符插入一个换行符(CRLF),这是 MIME 的特殊要求。
3. API 令牌与凭证
许多 API 使用 Base64 编码凭证:
- HTTP Basic Auth:
Authorization: Basic dXNlcjpwYXNz(user:pass的 Base64) - API Key:部分平台分发的 Key 实质是随机字节的 Base64 表示
4. JWT(JSON Web Token)
JWT 由三部分组成,Header 和 Payload 均使用 Base64 URL-safe 编码:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
5. Source Map 与 WASM
前端构建产物的 Source Map 和 WebAssembly 模块在特定场景下也使用 Base64 编码嵌入。
常见陷阱与误区
陷阱一:Base64 不是加密
Base64 是编码而非加密。任何人都能解码,它不提供任何保密性。将密码或敏感信息 Base64 编码后存储,等于明文存储。
陷阱二:膨胀被忽视
33% 的膨胀在大文件场景影响显著。一个 10MB 的图片 Base64 后约 13.3MB。在 API 响应中传递大体积 Base64 数据会拖慢传输和解析。
陷阱三:编码前后的字符集混淆
文本字符串 "Hello" 先经 UTF-8 编码为字节,再 Base64 编码。不同字符编码(UTF-8 vs GBK)会产生不同的 Base64 结果。处理中文等非 ASCII 文本时务必先统一为 UTF-8。
陷阱四:填充符 = 导致问题
部分系统对 URL 中的 = 处理不当。URL-safe Base64 通常省略 =,但解码时需补齐至 4 的倍数。一些库自动处理,一些则需要手动补齐。
陷阱五:换行符处理
MIME Base64 每 76 字符插入换行。如果用标准 Base64 解码器处理 MIME 格式数据,需先移除换行符。
各语言实现参考
| 语言 | 编码 | 解码 |
|---|---|---|
| JavaScript(浏览器) | btoa(str) |
atob(b64) |
| Node.js | Buffer.from(str).toString('base64') |
Buffer.from(b64, 'base64') |
| Python | base64.b64encode(data) |
base64.b64decode(b64) |
| Go | base64.StdEncoding.EncodeToString(data) |
base64.StdEncoding.DecodeString(b64) |
| Java | Base64.getEncoder().encodeToString(bytes) |
Base64.getDecoder().decode(b64) |
浏览器注意事项
btoa() / atob() 仅处理 Latin1 字符。编码中文需先转换:
const encoded = btoa(unescape(encodeURIComponent('中文')));
const decoded = decodeURIComponent(escape(atob(encoded)));
或使用现代 API TextEncoder 配合手动 Base64 实现。
性能与最佳实践
- 小于 4KB 的内联资源可用 Base64,更大文件用二进制传输
- 超过 1MB 的数据避免用 Base64,改用 Blob URL 或 multipart 上传
- 高频场景使用原生 API 而非纯 JS 实现
- 数据库存储 Base64 字符串会增大索引体积,优先存二进制
- 缓存 Base64 解码结果,避免重复计算