填充规则与作用
Base64 每次处理 3 字节并输出 4 个字符,输入长度可能不是 3 的倍数,最后不足的部分就用 = 补齐,因此输出长度永远是 4 的倍数。填充的作用不是补数据,而是让解码器知道最后一组里哪些位是有效位:余 1 字节时补两个等号,余 2 字节时补一个等号。RFC 4648 允许在特定上下文中省略填充(URL 安全变体、令牌拼接),这时解码方需要自行补齐才能解出原始数据。
基本信息
| 余 1 字节 | 补两个等号,输出 4 个字符 |
|---|---|
| 余 2 字节 | 补一个等号,输出 4 个字符 |
| 余 0 字节 | 无需填充 |
| 输出长度 | 始终为 4 的倍数 |
| 省略填充场景 | URL 安全变体、令牌、部分接口约定 |
| 解码要求 | 缺失填充时通常需补齐到 4 的倍数再解 |
典型使用场景
- 接口联调:两端对是否保留填充约定不一致,导致解码报长度错误
- 令牌解析:载荷与签名部分通常省略填充,需要先补齐再解码
- 配置拼接:手工截取 Base64 片段时容易丢掉尾部等号
- 数据校验:用长度是否为 4 的倍数快速判断内容是否完整
- 跨语言实现:不同库对缺失填充的容忍度不同,需统一处理
填充观察与补齐
填充观察与补齐
printf 'a' | base64 # YQ==:余 1 字节,两个等号
printf 'ab' | base64 # YWI=:余 2 字节,一个等号
printf 'abc' | base64 # YWJj:整除,无填充
# 缺失填充时手动补齐(按长度对 4 取余判断要补几个等号)
python -c "s='YQ'; s += '=' * (-len(s) % 4); print(s)" # YQ==
python -c "import base64; print(base64.b64decode('YQ==' ))" # b'a'
# 校验完整性:长度必须是 4 的倍数
python -c "print(len('YWJj') % 4)" # 0 表示长度合法填充与长度规则
| 输入字节数 | 有效位情况 | 填充符数量 |
|---|---|---|
| 1 | 6 位有效 + 2 位补零 | 2 个等号 |
| 2 | 12 位有效 + 4 位补零 | 1 个等号 |
| 3 | 24 位全有效 | 无 |
| 4 | 3 字节整块 + 1 字节余 | 2 个等号 |
| 5 | 3 字节整块 + 2 字节余 | 1 个等号 |
| 6 | 两个整块 | 无 |
省略填充不是「更简洁的等价写法」而是另一种约定:解码端必须知道当前内容属于哪种约定。生产接口应在文档里明确「是否保留填充」,并在实现里做兼容(先尝试原样解码,失败后补齐再解)。
不要手工删改尾部的等号来「清理」数据:等号位置与数量决定最后字节的还原,丢掉或改写会导致解出的内容缺少尾部字节,且不会总是报错——它可能静默产出错误数据。
不同库的严格程度不同:有的要求长度必须是 4 的倍数,有的接受缺失填充,有的还会忽略空白字符。跨语言接口出现「一边能解一边报错」时,先检查长度与填充,再检查字母表(标准还是 URL 安全)。