base64 模块 —— 二进制与文本的桥梁
一句话概括:
base64将任意二进制数据编码为纯 ASCII 字符串,让图片、密钥、压缩包等二进制内容能安全穿越"只认文本"的协议(HTTP 头、JSON、Email、URL)。
0. 思维导图
1. 是什么 —— Base64 编码原理
1.1 核心思想
计算机内部一切皆二进制,但许多协议(SMTP 邮件、JSON、HTTP 头)只接受可打印 ASCII 文本。Base64 的解决方案:把每 3 个字节(24 位)重新切分为 4 组,每组 6 位,再查表映射为可打印字符。
上图演示了
"Hel"→"SGVs"的编码过程。"Hello"完整编码为"SGVsbG8=",末尾=是填充字符。
1.2 编码表
Base64 字母表共 64 个字符:
| 值范围 | 字符 | 数量 |
|---|---|---|
| 0–25 | A–Z | 26 |
| 26–51 | a–z | 26 |
| 52–61 | 0–9 | 10 |
| 62 | +(标准)/ -(URL 安全) | 1 |
| 63 | /(标准)/ _(URL 安全) | 1 |
| 填充 | = | — |
1.3 Padding 规则
| 原始字节数 mod 3 | 补零位数 | Base64 填充 = 数 | 示例 |
|---|---|---|---|
| 0 | 0 | 0 | "Hel" → "SGVs" |
| 1 | 4 | 2 | "He" → "SGU=" |
| 2 | 2 | 1 | "Hel" + "lo" → "bG8=" |
关键:编码后长度一定是 4 的倍数,不足则用
=补齐。
1.4 数据膨胀
编码后体积 = ceil(原始字节数 / 3) × 4,即约 1.33 倍(33% 膨胀)。
2. 为什么需要 —— 典型痛点与动机
| 痛点 | 没有 Base64 会怎样 | Base64 如何解决 |
|---|---|---|
| JSON 不支持二进制 | 无法在 JSON 中传图片/文件 | 编码为字符串嵌入 |
| Email (SMTP) 只传 7-bit ASCII | 二进制附件被截断/乱码 | MIME Base64 编码传输 |
URL 中 + / = 有特殊含义 | 标准 Base64 放进 URL 会破坏语义 | urlsafe 变体替换为 - _ |
| HTML 内嵌小图片 | 需额外 HTTP 请求 | Data URI 直接嵌入 |
| HTTP Basic Auth | 无法在 Header 中传 user:pass | 编码后放入 Authorization 头 |
3. 怎么做 —— 模块架构与 API
3.1 模块架构总览
3.2 标准 Base64 编解码
base64.b64encode(s, altchars=None)
将字节对象 s 编码为 Base64。
- 参数:
s:bytes,待编码的二进制数据altchars:bytes,长度 2,用于替换+和/
- 返回值:
bytes,编码结果
base64.b64decode(s, altchars=None, validate=False)
将 Base64 编码数据解码为原始字节。
- 参数:
s:bytes或str,待解码数据altchars:bytes,长度 2,替代字符validate:bool,若为True则严格校验非字母表字符,非法时抛binascii.Error
- 返回值:
bytes,解码结果
import base64
# ---- 编码 ----
text = "Hello, World!" # 原始字符串
text_bytes = text.encode('utf-8') # 1. 先转为 bytes
encoded = base64.b64encode(text_bytes) # 2. Base64 编码
print(f"原始数据: {text_bytes}") # b'Hello, World!'
print(f"编码结果: {encoded}") # b'SGVsbG8sIFdvcmxkIQ=='
# ---- 解码 ----
decoded_bytes = base64.b64decode(encoded) # 3. Base64 解码
decoded_text = decoded_bytes.decode('utf-8') # 4. bytes → str
print(f"解码结果: {decoded_text}") # Hello, World!3.3 URL 安全 Base64 编解码
URL 中 + 和 / 是保留字符,标准 Base64 会破坏 URL 语义。urlsafe 变体用 - 替换 +,_ 替换 /。
base64.urlsafe_b64encode(s) / base64.urlsafe_b64decode(s)
import base64
# 对比标准与 urlsafe
data = b'\xfb\xff\xbf' # 会产生 + / 的二进制数据
std_encoded = base64.b64encode(data) # 标准 Base64
url_encoded = base64.urlsafe_b64encode(data) # URL 安全 Base64
print(f"标准编码: {std_encoded}") # b'++/v'
print(f"URL安全编码: {url_encoded}") # b'--_v'
# urlsafe_b64decode 也能解码标准编码(自动处理 + /)
decoded = base64.urlsafe_b64decode(url_encoded)
print(f"解码结果: {decoded}") # b'\xfb\xff\xbf'本质:
urlsafe_b64encode(s)等价于b64encode(s, altchars=b'-_')。
3.4 MIME 多行编解码
邮件附件等场景需要符合 RFC 2045 的格式:每 76 字符插入换行符 \n。
base64.encodebytes(s) / base64.decodebytes(s)
import base64
# 编码:自动每 76 字符换行
long_data = b"This is a long text that will be split into multiple lines for email transmission."
encoded = base64.encodebytes(long_data)
print("MIME 编码结果:")
print(encoded.decode('utf-8')
# VGhpcyBpcyBhIGxvbmcgdGV4dCB0aGF0IHdpbGwgYmUgc3BsaXQgaW50byBtdWx0aXBs
# ZSBsaW5lcyBmb3IgZW1haWwgdHJhbnNtaXNzaW9uLg==
# 解码:自动忽略换行符
decoded = base64.decodebytes(encoded)
print(f"解码结果: {decoded.decode('utf-8')}")3.5 Base32 与 Base16
import base64
data = "Hello, World!".encode('utf-8')
# Base32:A-Z + 2-7,大小写不敏感,膨胀率 1.6x
b32_enc = base64.b32encode(data)
print(f"Base32: {b32_enc}") # b'JBSWY3DPFQQFO33SNRSCC==='
# Base16:0-9 + A-F,即十六进制,膨胀率 2.0x
b16_enc = base64.b16encode(data)
print(f"Base16: {b16_enc}") # b'48656C6C6F2C20576F726C6421'
# Base32 解码(casefold=True 允许小写)
b32_dec = base64.b32decode(b'sgvsy3dpfqqfo33snrscc===', casefold=True)
print(f"Base32 解码: {b32_dec.decode('utf-8')}") # Hello, World!
# Base16 解码(casefold=True 允许小写)
b16_dec = base64.b16decode(b'48656c6c6f', casefold=True)
print(f"Base16 解码: {b16_dec.decode('utf-8')}") # Hello4. 编码变体对比表
| 特性 | Standard Base64 | URL-safe Base64 | MIME Base64 | Base32 | Base16 (Hex) |
|---|---|---|---|---|---|
| 字母表 | A-Za-z0-9+/ | A-Za-z0-9-_ | A-Za-z0-9+/ | A-Z2-7 | 0-9A-F |
| 填充 | = | = | = | = | 无 |
| 换行 | 无 | 无 | 每 76 字符 | 无 | 无 |
| 膨胀率 | 1.33x | 1.33x | ~1.35x(含换行) | 1.60x | 2.00x |
| URL 安全 | 否 | 是 | 否 | 是 | 是 |
| 大小写敏感 | 是 | 是 | 是 | 否(可配置) | 否(可配置) |
| Python 函数 | b64encode/decode | urlsafe_b64encode/decode | encodebytes/decodebytes | b32encode/decode | b16encode/decode |
| 典型场景 | 通用编码 | JWT、URL 参数 | 邮件附件 | DNS、OTP | 调试、哈希摘要 |
5. Base64 vs Hex vs binascii 对比表
| 维度 | base64.b64encode | base64.b16encode (Hex) | binascii.hexlify | binascii.b2a_base64 |
|---|---|---|---|---|
| 输出字母 | A-Za-z0-9+/= | 0-9A-F | 0-9a-f(小写) | A-Za-z0-9+/=\n |
| 膨胀率 | 1.33x | 2.00x | 2.00x | ~1.35x |
| 可读性 | 中 | 高 | 高 | 中 |
| URL 安全 | 需 urlsafe 变体 | 天然安全 | 天然安全 | 否 |
| 换行符 | 无 | 无 | 无 | 末尾有 \n |
| 输入类型 | bytes | bytes | bytes | bytes |
| 输出类型 | bytes | bytes | bytes | bytes |
| 适用场景 | 通用传输 | 调试/哈希 | 调试/哈希 | 兼容旧接口 |
import base64
import binascii
data = b"Hello"
print(f"base64.b64encode: {base64.b64encode(data)}") # b'SGVsbG8='
print(f"base64.b16encode: {base64.b16encode(data)}") # b'48656C6C6F'
print(f"binascii.hexlify: {binascii.hexlify(data)}") # b'48656c6c6f'(小写)
print(f"binascii.b2a_base64: {binascii.b2a_base64(data)}") # b'SGVsbG8=\n'(带换行)6. 实战场景
6.1 图片编码与 Data URI
Data URI 允许将图片直接嵌入 HTML/CSS,减少 HTTP 请求,适合小图标和内联图片。
import base64
import struct
import zlib
# ---- 生成一个 1x1 红色 PNG 图片(纯代码,无需文件) ----
def create_1x1_red_png() -> bytes:
"""生成 1x1 红色像素的 PNG 图片字节。"""
# PNG 签名
signature = b'\x89PNG\r\n\x1a\n'
# IHDR 块:宽1 高1 8位色 RGB
ihdr_data = struct.pack('>IIBBBBB', 1, 1, 8, 2, 0, 0, 0)
ihdr_crc = zlib.crc32(b'IHDR' + ihdr_data) & 0xffffffff
ihdr = struct.pack('>I', 13) + b'IHDR' + ihdr_data + struct.pack('>I', ihdr_crc)
# IDAT 块:1x1 红色像素
raw_data = b'\x00\xff\x00\x00' # filter byte + R G B
compressed = zlib.compress(raw_data)
idat_crc = zlib.crc32(b'IDAT' + compressed) & 0xffffffff
idat = struct.pack('>I', len(compressed)) + b'IDAT' + compressed + struct.pack('>I', idat_crc)
# IEND 块
iend_crc = zlib.crc32(b'IEND') & 0xffffffff
iend = struct.pack('>I', 0) + b'IEND' + struct.pack('>I', iend_crc)
return signature + ihdr + idat + iend
png_bytes = create_1x1_red_png() # 生成 PNG 二进制数据
b64_str = base64.b64encode(png_bytes).decode('utf-8') # 编码为 Base64 字符串
# ---- 构建 Data URI ----
data_uri = f"data:image/png;base64,{b64_str}"
print(f"Data URI 长度: {len(data_uri)} 字符")
# ---- 嵌入 HTML ----
html = f'<img src="{data_uri}" alt="1x1 red pixel" width="100" height="100">'
print(f"HTML 标签: {html[:80]}...")
# ---- 从 Data URI 还原图片 ----
prefix = "data:image/png;base64,"
if data_uri.startswith(prefix):
extracted_b64 = data_uri[len(prefix):] # 去掉前缀
restored_png = base64.b64decode(extracted_b64) # 解码
print(f"还原 PNG 大小: {len(restored_png)} 字节")
print(f"数据一致: {restored_png == png_bytes}") # True6.2 邮件附件(MIME)
import base64
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
def create_email_with_attachment(
sender: str,
recipient: str,
subject: str,
body: str,
attachment_path: str
) -> MIMEMultipart:
"""创建带附件的邮件对象。"""
msg = MIMEMultipart() # 1. 创建多部分邮件
msg['From'] = sender
msg['To'] = recipient
msg['Subject'] = subject
msg.attach(MIMEText(body, 'plain', 'utf-8')) # 2. 添加正文
with open(attachment_path, 'rb') as f: # 3. 读取附件二进制
part = MIMEBase('application', 'octet-stream')
part.set_payload(f.read()
encoders.encode_base64(part) # 4. Base64 编码附件
part.add_header( # 5. 设置附件头
'Content-Disposition',
f'attachment; filename="{attachment_path}"'
)
msg.attach(part)
return msg
# 使用示例(需要真实 SMTP 服务器才能发送):
# msg = create_email_with_attachment(
# sender="me@example.com",
# recipient="you@example.com",
# subject="Report",
# body="Please find the report attached.",
# attachment_path="report.pdf"
# )
# with smtplib.SMTP('smtp.example.com', 587) as server:
# server.starttls()
# server.login('user', 'password')
# server.send_message(msg)6.3 JWT Token 解析
JWT (JSON Web Token) 的 Header 和 Payload 使用 URL-safe Base64 编码(无 padding)。
import base64
import json
def decode_jwt_payload(token: str) -> dict:
"""解码 JWT 的 Payload 部分(不验证签名,仅解析内容)。"""
parts = token.split('.') # 1. JWT 由三部分组成
if len(parts) != 3:
raise ValueError("无效的 JWT 格式")
payload_b64 = parts[1] # 2. 取 Payload 部分
# JWT 使用无 padding 的 urlsafe Base64,需补齐 padding
padding = 4 - len(payload_b64) % 4 # 3. 计算需要补的 = 数
if padding != 4:
payload_b64 += '=' * padding
payload_bytes = base64.urlsafe_b64decode(payload_b64) # 4. URL-safe 解码
payload = json.loads(payload_bytes.decode('utf-8')) # 5. JSON 解析
return payload
# 模拟一个 JWT(此 token 仅用于演示,非真实签发)
demo_jwt = (
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ."
"SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
)
payload = decode_jwt_payload(demo_jwt)
print(f"JWT Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
# {
# "sub": "1234567890",
# "name": "John Doe",
# "iat": 1516239022
# }安全警告:此代码仅解析 JWT 内容,不验证签名。在生产环境中,必须使用
PyJWT等库验证签名后再信任 Payload 数据。
6.4 HTTP Basic Auth
import base64
def make_basic_auth_header(username: str, password: str) -> dict:
"""生成 HTTP Basic Authentication 请求头。"""
credentials = f"{username}:{password}" # 1. 拼接 user:pass
encoded = base64.b64encode(credentials.encode('utf-8')).decode('utf-8') # 2. Base64 编码
return {"Authorization": f"Basic {encoded}"} # 3. 放入 Header
def parse_basic_auth(header_value: str) -> tuple:
"""从 Basic Auth 头中提取用户名和密码。"""
scheme, _, token = header_value.partition(' ') # 4. 分离 "Basic" 和 token
if scheme.lower() != 'basic':
raise ValueError("非 Basic Auth")
decoded = base64.b64decode(token).decode('utf-8') # 5. 解码
username, _, password = decoded.partition(':') # 6. 分离 user:pass
return username, password
# 编码
headers = make_basic_auth_header("myuser", "mypassword123")
print(f"请求头: {headers}")
# {'Authorization': 'Basic bXl1c2VyOm15cGFzc3dvcmQxMjM='}
# 解码
user, pwd = parse_basic_auth(headers['Authorization'])
print(f"用户名: {user}, 密码: {pwd}")
# 用户名: myuser, 密码: mypassword1236.5 URL 安全编码实战
import base64
import urllib.parse
# 场景:在 URL 查询参数中传递二进制 token
raw_token = b'\x00\x01\x02\xfb\xff\xbf\xfe' # 含特殊字节的 token
# 错误做法:标准 Base64 直接放 URL
std_b64 = base64.b64encode(raw_token).decode('utf-8')
print(f"标准 Base64: {std_b64}") # AAEK++//vg==(含 + / =)
url_with_std = f"https://api.example.com/verify?token={std_b64}"
print(f"标准 URL: {url_with_std}")
# + / = 会被 URL 编码为 %2B %2F %3D,导致 token 变长且混乱
# 正确做法:urlsafe 编码
safe_b64 = base64.urlsafe_b64encode(raw_token).decode('utf-8')
print(f"URL安全 Base64: {safe_b64}") # AAEK--_v_g==(- _ 替代 + /)
url_with_safe = f"https://api.example.com/verify?token={safe_b64}"
print(f"安全 URL: {url_with_safe}")
# 服务端解码
query_token = safe_b64.rstrip('=') # URL 中常去掉 padding
# 补齐 padding 后解码
padding_needed = 4 - len(query_token) % 4
if padding_needed != 4:
query_token += '=' * padding_needed
restored = base64.urlsafe_b64decode(query_token)
print(f"还原 token: {restored == raw_token}") # True7. 高级主题
7.1 安全解码函数封装
import base64
import binascii
def safe_b64decode(s: str | bytes, urlsafe: bool = False) -> bytes | None:
"""
安全地解码 Base64 字符串。
- 自动补齐 padding
- 捕获所有异常,失败返回 None
- 支持 urlsafe 模式
"""
if isinstance(s, bytes): # 1. 统一转为 str
s = s.decode('utf-8', 'ignore')
s = s.strip() # 2. 去除首尾空白
s = ''.join(s.split()) # 3. 去除所有换行/空格
# 4. 补齐 padding
padding_needed = len(s) % 4
if padding_needed:
s += '=' * (4 - padding_needed)
# 5. 选择解码函数
decode_func = base64.urlsafe_b64decode if urlsafe else base64.b64decode
try:
return decode_func(s)
except (binascii.Error, TypeError, ValueError):
return None
# 测试
print(safe_b64decode("SGVsbG8")) # b'Hello'(自动补 padding)
print(safe_b64decode("SGVsbG8=")) # b'Hello'
print(safe_b64decode("Invalid$String")) # None
print(safe_b64decode("--_v", urlsafe=True)) # b'\xfb\xff\xbf'7.2 大文件分块编解码
直接将大文件读入内存可能导致 OOM,应分块处理。
import base64
def encode_file_chunked(input_path: str, output_path: str, chunk_size: int = 57) -> None:
"""
分块读取文件并 Base64 编码。
chunk_size=57 是因为 57 字节编码后恰好为 76 字符(MIME 标准行宽),
且 57 是 3 的倍数,不会产生跨块 padding 问题。
"""
with open(input_path, 'rb') as fin, open(output_path, 'w') as fout:
while True:
chunk = fin.read(chunk_size) # 1. 读取 57 字节
if not chunk:
break
encoded = base64.b64encode(chunk).decode('utf-8') # 2. 编码
fout.write(encoded + '\n') # 3. 写入一行
def decode_file_chunked(input_path: str, output_path: str, chunk_size: int = 8192) -> None:
"""
分块读取 Base64 文件并解码。
读取块大小必须是 4 的倍数,否则解码会出错。
"""
read_size = (chunk_size // 4) * 4 # 1. 确保是 4 的倍数
with open(input_path, 'r') as fin, open(output_path, 'wb') as fout:
while True:
chunk = fin.read(read_size) # 2. 读取
if not chunk:
break
chunk = chunk.replace('\n', '') # 3. 去除换行
if not chunk:
continue
decoded = base64.b64decode(chunk) # 4. 解码
fout.write(decoded) # 5. 写入
# 使用示例:
# encode_file_chunked('large_video.mp4', 'encoded.txt')
# decode_file_chunked('encoded.txt', 'restored.mp4')7.3 安全性警告
Base64 是编码,不是加密! 任何人都能解码。切勿用 Base64 存储/传输密码、私钥等敏感信息。
8. 最佳实践对比表
| 场景 | 推荐做法 | 不推荐做法 | 原因 |
|---|---|---|---|
| URL 中传二进制 | urlsafe_b64encode | b64encode + urllib.parse.quote | 前者一步到位,后者双重编码浪费 |
| JSON 嵌入二进制 | b64encode(...).decode('utf-8') | 直接放 bytes 对象 | JSON 不支持 bytes |
| 邮件附件 | encodebytes / email.encoders | 手动 b64encode + 拼换行 | 标准库已封装 MIME 格式 |
| JWT Token | urlsafe_b64encode + 去 padding | b64encode | JWT 规范要求 urlsafe 无 padding |
| 大文件编码 | 分块 57 字节读取 | f.read() 一次性读取 | 避免 OOM |
| 存储密码 | hashlib + salt | Base64 编码 | Base64 可逆,不安全 |
| 调试打印二进制 | b16encode / hexlify | b64encode | 十六进制更直观可读 |
| 去除 padding | rstrip('=') | replace('=', '') | replace 会误删数据中的 = |
9. 常见陷阱 / FAQ
Q1: 为什么解码时报 binascii.Error: Incorrect padding?
原因:Base64 字符串长度不是 4 的倍数,缺少 = 填充。
解决:自动补齐 padding。
import base64
def auto_padding_decode(s: str) -> bytes:
"""自动补齐 padding 后解码。"""
s = s.strip()
missing = len(s) % 4
if missing:
s += '=' * (4 - missing)
return base64.b64decode(s)
# JWT 等场景常省略 padding
print(auto_padding_decode("SGVsbG8")) # b'Hello'(自动补 1 个 =)Q2: b64decode 和 urlsafe_b64decode 能否互相解码?
可以。urlsafe_b64decode 内部会同时处理 +/ 和 -_,因此也能解码标准 Base64。但 b64decode 默认不认识 - 和 _。
import base64
data = b'\xfb\xff\xbf'
std = base64.b64encode(data) # b'++/v'
safe = base64.urlsafe_b64encode(data) # b'--_v'
# urlsafe_b64decode 可以解码两种格式
print(base64.urlsafe_b64decode(std)) # b'\xfb\xff\xbf' ✓
print(base64.urlsafe_b64decode(safe)) # b'\xfb\xff\xbf' ✓
# b64decode 只能解码标准格式
print(base64.b64decode(std)) # b'\xfb\xff\xbf' ✓
# print(base64.b64decode(safe)) # binascii.Error ✗Q3: 如何处理非 ASCII 字符?
Base64 操作的是 bytes,不是 str。必须先编码为字节(如 UTF-8),再进行 Base64 编码。
import base64
# 正确做法
text = "你好,世界!"
encoded = base64.b64encode(text.encode('utf-8')) # 先 UTF-8 编码
decoded = base64.b64decode(encoded).decode('utf-8') # 后 UTF-8 解码
print(decoded) # 你好,世界!
# 错误做法:直接传 str 给 b64encode
# base64.b64encode("你好") # TypeError: a bytes-like object is requiredQ4: encodebytes 和 b64encode 有什么区别?
| 差异 | b64encode | encodebytes |
|---|---|---|
| 换行符 | 无 | 每 76 字符插入 \n |
| 末尾换行 | 无 | 有 |
| 用途 | 通用 | MIME 邮件 |
| 等价关系 | — | b64encode + 插入换行 |
Q5: validate=True 有什么用?
默认情况下 b64decode 会静默忽略非 Base64 字符(如换行、空格)。设置 validate=True 后,遇到非法字符会抛出 binascii.Error。
import base64
import binascii
data_with_newlines = b"SGVs\nbG8=" # 含换行符
# 默认:忽略换行,正常解码
print(base64.b64decode(data_with_newlines)) # b'Hello'
# 严格模式:报错
try:
base64.b64decode(data_with_newlines, validate=True)
except binascii.Error as e:
print(f"验证失败: {e}") # Non-base64 digit foundQ6: Base64 编码后的字符串能直接比较吗?
不能。同一数据可能有多种合法的 Base64 表示(有无 padding、有无换行、标准 vs urlsafe)。应先解码再比较。
import base64
a = base64.b64encode(b"Hello") # b'SGVsbG8='
b = base64.urlsafe_b64encode(b"Hello") # b'SGVsbG8='(此例恰好相同)
c = b"SGVsbG8" # 无 padding
# 错误:字符串比较
print(a == c) # False
# 正确:解码后比较
print(base64.b64decode(a) == base64.b64decode(c + b'=')) # True术语表
| 术语 | 英文 | 含义 |
|---|---|---|
| Base64 | Base64 | 将二进制数据编码为 64 个可打印 ASCII 字符的方案 |
| Padding | Padding / 填充 | 用 = 补齐编码结果至 4 的倍数长度 |
| URL-safe | URL-safe / URL 安全 | 用 - _ 替代 + /,使编码结果可安全出现在 URL 中 |
| MIME | Multipurpose Internet Mail Extensions | 多用途互联网邮件扩展,定义了邮件中 Base64 的换行格式 |
| Data URI | Data URI Scheme | 将资源内嵌为 data: 开头的 URI,常配合 Base64 使用 |
| JWT | JSON Web Token | 基于 JSON 的开放标准令牌,使用 urlsafe Base64 无 padding 编码 |
| 膨胀率 | Expansion Ratio | 编码后体积与原始体积的比值,Base64 为 4/3 ≈ 1.33 |
| 字母表 | Alphabet | 编码使用的字符集,标准 Base64 为 A-Za-z0-9+/ |
| RFC 4648 | RFC 4648 | 定义 Base64/Base32/Base16 编码规范的标准文档 |
| binascii | binascii | Python 标准库中二进制与 ASCII 互转的底层模块,base64 依赖它 |
延伸阅读
| 资源 | 说明 |
|---|---|
| RFC 4648 — The Base16, Base32, and Base64 Data Encodings | Base 系列编码的权威规范 |
| RFC 2045 — MIME Part One | MIME 中 Base64 的换行规则定义 |
| RFC 7519 — JSON Web Token (JWT) | JWT 规范,使用 Base64url 编码 |
| Python 官方文档 — base64 | Python base64 模块完整 API 文档 |
| Base64 编码可视化工具 | 在线编码/解码与原理可视化 |
| PyJWT 库 | 生产级 JWT 签发与验证库 |
| Data URI Scheme — MDN | Data URI 的浏览器规范与用法 |
12. API 快速参考
| 函数 | 描述 | 输入 | 输出 | 主要用途 |
|---|---|---|---|---|
b64encode(s, altchars=None) | 标准 Base64 编码 | bytes | bytes | 通用二进制编码 |
b64decode(s, altchars=None, validate=False) | 标准 Base64 解码 | bytes/str | bytes | 解码通用 Base64 |
urlsafe_b64encode(s) | URL 安全 Base64 编码 | bytes | bytes | URL / JWT / 文件名 |
urlsafe_b64decode(s) | URL 安全 Base64 解码 | bytes/str | bytes | 解码 URL 安全 Base64 |
encodebytes(s) | MIME Base64 编码(76 字符换行) | bytes | bytes | 邮件附件 |
decodebytes(s) | MIME Base64 解码 | bytes | bytes | 解码 MIME Base64 |
b32encode(s) | Base32 编码 | bytes | bytes | 大小写不敏感场景 |
b32decode(s, casefold=False, map01=None) | Base32 解码 | bytes/str | bytes | 解码 Base32 |
b16encode(s) | Base16 (Hex) 编码 | bytes | bytes | 调试 / 可读性 |
b16decode(s, casefold=False) | Base16 (Hex) 解码 | bytes/str | bytes | 解码十六进制 |
总结
核心要点:
- 始终操作
bytes:编码输入和解码输出都是字节,字符串需先.encode('utf-8') - 选择合适的变体:URL 场景用
urlsafe,邮件用encodebytes,调试用b16encode - 注意 padding:解码时长度须为 4 的倍数,JWT 等场景常省略 padding 需手动补齐
- 大文件分块:每次读 57 字节(3 的倍数),避免跨块 padding 问题
- Base64 不是加密:编码可逆,切勿用于保护敏感信息
版本差异(标准库 → Python 3.14)
| 模块/特性 | 本文编写时 | Python 3.14 变化 |
|---|---|---|
datetime | utcnow() / utcfromtimestamp() | 3.12 起弃用,改用 datetime.now(tz=datetime.UTC) / fromtimestamp(ts, tz=datetime.UTC)(aware 对象) |
asyncio | 基础 API | 3.14 新增内省能力(asyncio.Task/Future 状态查询);3.11 起推荐 TaskGroup + asyncio.timeout() |
typing | 旧式 List/Dict | 3.9+ 内置泛型;3.10+ 联合类型 X | Y;3.12 type 语句;3.14 PEP 649 延迟注解 |
importlib | imp 模块 | imp 于 3.12 移除,统一使用 importlib |
| 压缩 | zlib/gzip/bz2/lzma | 3.14 新增 zstandard 标准库支持(PEP 784) |
pathlib | 基础路径操作 | 3.12+ 持续增强(Path.walk() 等),3.13 支持 is_relative_to() 等 |
| 往事清理 | — | 3.13 移除 cgi、telnetlib、crypt、audioop 等已废弃模块 |
本文讲解的模块核心 API 与使用模式在 3.14 中保持稳定;注意上述弃用/移除项,升级时优先用标准库推荐的替代方案。