开始之前
边看边操作在 Base64 编解码 中打开实际工作区→
Base64URL 是适用于 URL 和文件名的 Base64 变体:加号换成减号,斜杠换成下划线,填充等号通常省略。JWT 的 Header、Payload 和 Signature 三段都使用不带填充的 Base64URL,但解码出 Claims 并不等于验签成功。
用同一组字节对比字符表
UTF-8 文本“ÿ?”的标准 Base64 是 w78/,Base64URL 是 w78_。变化的只是最后一个字符表符号,解码后得到的字节完全相同。
示例
UTF-8 输入:ÿ?
标准 Base64:w78/
Base64URL:w78_理解等号只是填充
Base64 每三个字节输出四个字符。结尾不足三个字节时,等号只负责补齐四字符分组:余一个字节补两个等号,余两个字节补一个,刚好整除则不需要。
示例
输入字节数 mod 3 = 0 → 不填充
输入字节数 mod 3 = 1 → ==
输入字节数 mod 3 = 2 → =只在解码器需要时补位
JWT 分段可以先把减号和下划线换回标准字符,再补到四的倍数。如果长度除以四余一,说明内容本身不合法,不应该盲目追加等号。
示例
function decodeBase64Url(segment) {
if (segment.length % 4 === 1) throw new Error("Invalid Base64URL length");
const normalized = segment.replace(/-/g, "+").replace(/_/g, "/");
const padded = normalized + "=".repeat((4 - normalized.length % 4) % 4);
const bytes = Uint8Array.from(atob(padded), c => c.charCodeAt(0));
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}Java 8 直接使用 URL 解码器
java.util.Base64 已经区分标准、URL 和 MIME 变体。JWT Header 与 Payload 应使用 getUrlDecoder,不要先交给标准解码器再靠字符串替换修补。
示例
import java.nio.charset.StandardCharsets;
import java.util.Base64;
String payload = "eyJzdWIiOiIxMjMiLCJleHAiOjE5MDAwMDAwMDB9";
byte[] decoded = Base64.getUrlDecoder().decode(payload);
System.out.println(new String(decoded, StandardCharsets.UTF_8));
// {"sub":"123","exp":1900000000}解析之后仍要验签
解码只会展示任何人都能伪造的文本。信任 sub、role、exp、aud 等 Claims 前,服务端还必须使用可信密钥验签、固定允许算法,并检查 issuer、audience、时间和业务授权。
工具中的无填充 Base64URL
截图中格式已选择 Base64URL,并关闭等号填充。结果 w78_ 可以直接放进 URL 路径或参数,不会出现需要转义的斜杠和加号。

怎样选择正确的 Base64 变体
| 对比项 | 标准 Base64 | Base64URL / JWT |
|---|---|---|
| 第 62、63 个字符 | + 和 / | - 和 _ |
| 等号填充 | 通常保留 | JWT 通常省略 |
| 典型场景 | 文件、邮件、API Body | JWT、OAuth、URL 参数 |
| Java 8 API | Base64.getDecoder() | Base64.getUrlDecoder() |
要点总结
- Base64URL 只替换字符表,不会改变解码后的字节。
- JWT 分段按规范通常省略等号,不是数据丢失。
- 遇到减号和下划线时应使用 Base64URL 解码器。
- 读出 JWT Claims 不代表签名和授权已经验证。