正在加载,请稍候…

Base64 编码与解码:开发者实用指南

了解 Base64 是什么、如何工作、从数据 URL 到 JWT 的常见用例,以及如何在 JavaScript、Python 等语言中编码和解码 Base64。

Base64 编码与解码:开发者实用指南

什么是 Base64?

Base64 是一种二进制到文本的编码方案,使用 64 个可打印的 ASCII 字符来表示二进制数据:A-Za-z0-9+/(加上用于填充的 =)。名称“Base64”即源于此 64 字符字母表。

它专为解决特定问题而设计:某些系统(电子邮件协议、XML 文档、URL)仅处理文本而非原始二进制。Base64 允许你在纯文本环境中嵌入二进制数据——图像、文件、加密字节、数字签名等。

Base64 不是加密。 它没有密钥,也不提供安全性。解码对任何人来说都是简单且可逆的。其目的是兼容性编码,而非保密。

Base64 编码与解码:开发者实用指南 插图

Base64 的工作原理

Base64 的工作原理:

  1. 将输入字节按 3 个一组(24 位)分组
  2. 将每个 24 位组拆分为四个 6 位块
  3. 在 Base64 字母表中查找每个 6 位值(0–63 → A–Z、a–z、0–9、+、/)
  4. 如果输入字节数不是 3 的倍数,则添加 = 填充字符

示例:编码 "Man"

输入:    M        a        n
ASCII:   77       97       110
位:      01001101 01100001 01101110

24 位组: 010011 010110 000101 101110
查找:    T      W      F      u
输出:    TWFu

大小增加: Base64 输出始终是输入大小的 4/3(加上填充)。3 字节输入变为 4 个字符。1 MB 文件编码后约为 1.37 MB。

填充

如果输入长度不是 3 的倍数:

  • 剩余 1 字节 → 2 个 Base64 字符 + ==
  • 剩余 2 字节 → 3 个 Base64 字符 + =
"M"  → TWO= (1 字节输入 → 4 个字符,含 == 填充)
"Ma" → TWE= (2 字节输入 → 4 个字符,含 = 填充)
"Man"→ TWFu (3 字节输入 → 4 个字符,无填充)

URL 安全的 Base64

标准 Base64 使用 +/,它们在 URL 中有特殊含义。Base64url 替换:

  • +-
  • /_
  • 通常省略填充 =(因为 URL 中的 %3D 不美观)

用于:JWT、OAuth 令牌、许多 Web API。

在代码中编码和解码

JavaScript(浏览器)

// 浏览器内置函数:btoa(二进制到 ASCII)和 atob(ASCII 到二进制)

// 将字符串编码为 Base64
const encoded = btoa('Hello, World!');
// => 'SGVsbG8sIFdvcmxkIQ=='

// 将 Base64 解码为字符串
const decoded = atob('SGVsbG8sIFdvcmxkIQ==');
// => 'Hello, World!'

// ⚠️ btoa/atob 仅适用于 Latin-1 字符。
// 对于 Unicode 字符串,先编码为 UTF-8 字节:
function toBase64(str) {
  return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
    (_, p1) => String.fromCharCode(parseInt(p1, 16))
  ));
}

function fromBase64(b64) {
  return decodeURIComponent(atob(b64).split('').map(
    c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
  ).join(''));
}

// 或使用现代 TextEncoder 方法:
function toBase64Modern(str) {
  const bytes = new TextEncoder().encode(str);
  let binary = '';
  for (const b of bytes) binary += String.fromCharCode(b);
  return btoa(binary);
}

Base64 编码与解码:开发者实用指南 插图

JavaScript(Node.js)

// Node.js — Buffer
const text = 'Hello, World!';

// 编码
const encoded = Buffer.from(text).toString('base64');
// => 'SGVsbG8sIFdvcmxkIQ=='

// Base64url(无填充,URL 安全字符)
const encodedUrl = Buffer.from(text).toString('base64url');

// 解码
const decoded = Buffer.from('SGVsbG8sIFdvcmxkIQ==', 'base64').toString('utf8');
// => 'Hello, World!'

// 编码文件
const { readFileSync } = require('fs');
const fileBase64 = readFileSync('/path/to/image.png').toString('base64');

Python

import base64

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

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

# URL 安全的 Base64
url_encoded = base64.urlsafe_b64encode(b'binary data here')
url_decoded = base64.urlsafe_b64decode(url_encoded)

# 编码文件
with open('image.png', 'rb') as f:
    img_b64 = base64.b64encode(f.read()).decode()

Go

import "encoding/base64"

// 编码
encoded := base64.StdEncoding.EncodeToString([]byte("Hello, World!"))
// => "SGVsbG8sIFdvcmxkIQ=="

// URL 安全(无填充)
encodedUrl := base64.RawURLEncoding.EncodeToString([]byte("Hello, World!"))

// 解码
decoded, err := base64.StdEncoding.DecodeString("SGVsbG8sIFdvcmxkIQ==")

常见用例

1. 数据 URL(HTML/CSS 中的内联图像)

将图像直接嵌入 HTML 或 CSS,无需单独的 HTTP 请求:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." />
.icon {
  background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL...');
}

适用于小图标和关键图像,无需单独请求。避免用于大图像——Base64 会使大小增加 33%,并阻止缓存。

Base64 编码与解码:开发者实用指南 插图

2. JWT(JSON Web Token)

JWT 由三个 Base64url 编码的部分组成,以点分隔:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
^header^                              ^payload^                        ^signature^

解码头部:atob('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'){"alg":"HS256","typ":"JWT"}

3. 电子邮件附件(MIME)

SMTP 设计用于 ASCII 文本。电子邮件客户端将附件编码为 MIME 部分中的 Base64:

Content-Type: image/jpeg
Content-Transfer-Encoding: base64

/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsL...

4. 在 JSON 中存储二进制数据

JSON 不支持二进制。当 API 需要在 JSON 响应中返回二进制数据(例如缩略图、加密 blob)时,Base64 编码是标准方法:

{
  "id": "file-123",
  "thumbnail": "data:image/webp;base64,UklGRiQAAABXRUJQVlA4...",
  "encrypted_key": "c2VjcmV0a2V5..."
}

5. 基本认证头

HTTP 基本认证将凭据发送为 Base64(username:password)

Authorization: Basic dXNlcjpwYXNzd29yZA==

atob('dXNlcjpwYXNzd29yZA==')user:password

这是 Base64,不是加密——使用基本认证时务必使用 HTTPS。编码仅防止偶然观察,而非拦截。

6. 加密密钥和证书

PEM 文件(以 -----BEGIN CERTIFICATE----- 开头的文件)包含 Base64 编码的 DER 二进制数据:

-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIUMTIzNDU2Nzg5MEFCQ0RFRjAxMjM0NTY3ODkwMTIz...
-----END CERTIFICATE-----

常见错误

用编码代替加密: Base64 可轻易逆转。切勿仅用 Base64 来“保护”敏感数据。

浏览器中未处理 Unicode: btoa() 在遇到非 Latin-1 字符时会抛出异常。请使用 TextEncoder 或上面展示的百分号编码方法。

解码时忘记填充: 某些系统会去掉 = 填充。解码时可能需要重新添加:b64 + '='.repeat((4 - b64.length % 4) % 4)

使用错误的变体: 标准 Base64(+/)与 Base64url(-_)混淆会导致解码失败。

→ 使用 Base64 字符串转换器 即时编码和解码 Base64 字符串。