你在浏览器里见过这样的字符串吗?
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
这一长串乱码,就是 Base64。
它看起来像乱码,但背后有个简单的设计思路:把二进制数据变成 printable 字符。
这篇文章从 Base64 的原理讲起,演示 5 个你在实际开发中经常遇到的场景。每个场景都有代码示例,可以直接拿去用。
Base64 到底是什么?
把一段话说清楚:Base64 是一种编码方式,不是加密方式。
编码和加密的区别:
- 编码:任何人都能解码,目的是让数据能在特定渠道传输
- 加密:只有持有密钥的人能解码,目的是保护隐私
Base64 把每 3 个字节(24 位)的数据,转换成 4 个可打印字符。这 4 个字符来自 64 个预设字符:A-Z、a-z、0-9、+、/。
为什么是 64 个字符?因为 2^6 = 64。6 位二进制可以表示 64 种状态,正好对应一个 Base64 字符。
转换过程很简单:
原始 3 字节: 01234567 89abcdef 01234567
按6位分组: 012345 6789ab cdef01 234567
对应字符: T G 1 j
输出 4 个字符,输入 3 个字节。所以 Base64 编码后的数据比原始数据大约 33%。
场景1:把图片转成 Base64 直接嵌入 HTML
这是最常见的用法。不需要上传图片到服务器,直接把图片数据写在 HTML 里。
import base64
# 读取图片文件
with open('photo.png', 'rb') as f:
image_data = f.read()
# 转成 Base64
b64_string = base64.b64encode(image_data).decode('utf-8')
# 嵌入 HTML
html = f'''
<img src="data:image/png;base64,{b64_string}" alt="图片">
'''
with open('image_inlined.html', 'w') as f:
f.write(html)
注意事项:
- 图片越大,HTML 文件越大。超过 100KB 的图片不建议内嵌
- 移动端加载内嵌图片会比较慢
- 适合小图标、logo 这类小图片
场景2:URL 安全 Base64 编码
标准 Base64 用了 + 和 / 字符。这两个字符在 URL 中有特殊含义,会导致问题。
解决方法:用 - 替换 +,用 _ 替换 /,去掉末尾的 =。
import base64
# 普通 Base64 编码
normal_b64 = base64.b64encode(b'hello world!').decode()
# 结果: aGVsbG8gd29ybGQh
# URL 安全的 Base64 编码
url_safe = base64.urlsafe_b64encode(b'hello world!').decode()
# 结果: aGVsbG8gd29ybGQh
# 去掉末尾的 = 填充符(可选)
url_safe = url_safe.rstrip('=')
什么时候用 URL 安全 Base64?
- 生成短链接参数
- JWT token 传递
- API 查询参数
- URL 中传输任意数据
场景3:用 Base64 做简单的 API 参数传输
假设你要通过 URL 参数传一个 JSON 对象给服务端:
import base64
import json
# 原始数据
data = {
"user_id": 12345,
"permissions": ["read", "write", "delete"],
"expires": "2026-12-31"
}
# 编码
encoded = base64.urlsafe_b64encode(json.dumps(data).encode()).decode().rstrip('=')
print(encoded)
# 结果类似: eyJ1c2VyX2lkIjoxMjM0NSwicGVybWlzc2lvbnMiOlsicmVhZCIsIndyaXRlIiwiZGVsZXRlIl0sImV4cGlyZXMiOiIyMDI2LTEyLTMxIn0
# 解码
decoded = base64.urlsafe_b64decode(encoded + '==')
result = json.loads(decoded)
print(result)
# {'user_id': 12345, 'permissions': ['read', 'write', 'delete'], 'expires': '2026-12-31'}
注意: Base64 编码不等于加密。任何人都能看到你的数据内容。如果需要保密,先加密再编码。
场景4:API 签名验证中的 Base64
很多 API 的签名验证流程会用到 Base64。比如 HMAC-SHA256 签名:
import hmac
import hashlib
import base64
def create_signature(secret_key, message):
"""用 HMAC-SHA256 生成签名"""
signature = hmac.new(
secret_key.encode('utf-8'),
message.encode('utf-8'),
hashlib.sha256
).digest()
# Base64 编码后传给服务端
return base64.b64encode(signature).decode('utf-8')
# 使用示例
secret = "my_api_secret_key"
message = "GET /api/v1/users 2026-06-10T09:00:00Z"
sig = create_signature(secret, message)
print(sig)
# 把 sig 放在请求头里:Authorization: Bearer <sig>
这是很多 API 的标准做法:
- 服务端和客户端共享一个密钥
- 客户端用密钥对请求内容做签名
- 签名用 Base64 编码后放入请求头
- 服务端用同样的密钥验证签名
场景5:常见错误排查
用 Base64 踩过的那些坑:
错误1:字符数不对
import base64
# Base64 编码后的字符串长度必须是 4 的倍数
# 如果不是,需要补 = 填充
bad_string = "aGVsbG8gd29ybGQ" # 15 个字符,不是 4 的倍数
# 修复方法
padding = 4 - (len(bad_string) % 4)
if padding != 4:
bad_string += '=' * padding
result = base64.b64decode(bad_string).decode()
print(result) # hello world
错误2:URL 传输时 + 被转成了空格
这是老式 URL 编码的坑。+ 在 application/x-www-form-urlencoded 中会被转成空格。
import urllib.parse
import base64
# 编码
b64 = base64.urlsafe_b64encode(b'test data').decode()
# 用 URL 安全的方式传输
url_encoded = urllib.parse.quote(b64, safe='')
# 解码回来
decoded_b64 = urllib.parse.unquote(url_encoded)
result = base64.urlsafe_b64decode(decoded_b64).decode()
print(result) # test data
错误3:中文字符直接 Base64 编码乱码
import base64
# 错误做法(直接对中文字符串编码)
wrong = base64.b64encode('你好世界'.encode()).decode()
# 结果: 5L2g5aW95bel5LiA
# 正确做法(先确保 UTF-8 编码)
correct = base64.b64encode('你好世界'.encode('utf-8')).decode()
# 结果: 5L2g5aW95bel5LiA
# 解码回来
print(base64.b64decode(correct).decode('utf-8')) # 你好世界
记住: 中文字符串在 Base64 编码前,先确认编码格式是 UTF-8。
Base64 vs 其他编码方式
| 编码方式 | 用途 | 可读性 | 压缩率 | 适合场景 |
|---|---|---|---|---|
| Base64 | 二进制转文本 | 不可读 | -33% | 传输、嵌入 |
| Hex | 二进制转十六进制 | 不可读 | +100% | 哈希值显示 |
| UTF-8 | 字符编码 | 部分可读 | 可变 | 文本存储 |
| Gzip+Base64 | 压缩后编码 | 不可读 | 压缩后变小 | 大数据传输 |
总结
Base64 不是什么高深的技术,但它的实用场景非常广。从图片内嵌、API 签名到 URL 参数传输,你几乎每天都在用它。
核心要点记住三点:
- Base64 不是加密,只是编码,任何人都能解码
- URL 传输记得用
urlsafe_b64encode,别被+和/坑了 - 长度问题:解码前先确保字符串长度是 4 的倍数
你有用 Base64 踩过什么坑?分享一下,让后来者少踩几个。