Javascript is required
实现原理发布于 2026-07-28更新于 2026-08-08审校于 2026-08-085 分钟阅读

Base64 编解码算法原理:3字节转4字节、= 填充符根因与 URL-Safe (RFC 4648) 变种

Base64 是一种将二进制数据转换为 64 个可打印 ASCII 字符的编码算法。为什么末尾经常出现 = 填充符?为什么在 URL 或 JWT Token 中必须使用 -_ 变种?本文拆解 Base64 的数学转换机制与 URL-Safe 变种。

Base64PaddingURL-SafeAlgorithm

一、问题概述:24-bit 组划分与末尾 = 填充符的由来

Base64 算法核心是将每 3 个字节(共 24 bit)按 6 个 bit 为一组切分为 4 个单元,每个单元的值(0 到 63)在索引表中映射为一个 ASCII 字符。当待编码的字节数不能被 3 整除时,末尾会产生余数:余数为 1 字节(8 bit)时,补 4 个 0 bit 凑齐 2 个 6-bit 单元,末尾补 2 个 =;余数为 2 字节(16 bit)时,补 2 个 0 bit 凑齐 3 个 6-bit 单元,末尾补 1 个 =

二、最小复现:标准 Base64 与 URL-Safe 变种编码对比

包含 +/ 的标准 Base64 在 URL 中传输时会被误判;以下代码展示两种编码形态的转化:

/* 标准 Base64:包含 + 和 / 以及末尾填充 = */
const stdBase64 = "a+b/c==";

/* 错误做法:直接拼接到 URL Query 中 */
// https://example.com/api?data=a+b/c==  (+ 变为空格,/ 被当作路径分隔符!)

/* URL-Safe Base64 (RFC 4648):+ 替换为 -,/ 替换为 _,且省略 = */
const urlSafeBase64 = "a-b_c";

三、根因分析:字符冲突与 HTTP/URL 语法的天然矛盾

在标准 Base64 字符表(A-Z, a-z, 0-9, +, /)中,+/ 恰好是 URL 语法中的保留分隔符。为了解决传输歧义,RFC 4648 提出了 Base64URL 规范:将 + 替换为 -(连字符),将 / 替换为 _(下划线),并允许在 JSON Web Token (JWT) 或 URL Query 中省略末尾对齐用的 = 符号。

四、推荐方案:标准 Base64 与 Base64URL 双向安全转换纯函数

1. 转为 URL-Safe:替换 +-/_,并可选剔除末尾的 = 填充符。2. 还原为标准 Base64:替换 -+_/,并根据 (4 - (len % 4)) % 4 补充末尾缺少的 =。3. 使用无填充 Base64URL 减小 JWT 传输体积。

五、完整代码:URL-Safe Base64 转换与无 Padding 还原工具函数

下面的 TypeScript 代码演示如何在标准 Base64 与 RFC 4648 URL-Safe Base64 变种之间做双向无损转换。

function toUrlSafeBase64(standardBase64: string, stripPadding = true): string {
  // 1. RFC 4648 替换 + -> - 以及 / -> _
  let urlSafe = standardBase64.replace(/\+/g, "-").replace(/\//g, "_");
  // 2. 如果开启 stripPadding,移除末尾的 = 填充符
  if (stripPadding) {
    urlSafe = urlSafe.replace(/=+$/, "");
  }
  return urlSafe;
}

function fromUrlSafeBase64(urlSafeBase64: string): string {
  // 1. 还原替换 - -> + 以及 _ -> /
  let base64 = urlSafeBase64.replace(/-/g, "+").replace(/_/g, "/");
  // 2. 计算补全末尾的 = 填充符
  const padLength = (4 - (base64.length % 4)) % 4;
  for (let i = 0; i < padLength; i++) {
    base64 += "=";
  }
  return base64;
}

const stdBase64 = "a+b/c==";
const urlSafe = toUrlSafeBase64(stdBase64, true);
console.log(urlSafe); // "a-b_c"
console.log(fromUrlSafeBase64(urlSafe)); // "a+b/c=="

六、常见错误方案

在未还原 -_ 以及未补齐 = 的情况下,直接将 JWT 载荷传给原生 atob 导致解码失败;对图片 Data URL 误用 URL-Safe 替换。

七、边界条件:非 4 的倍数字符串与严格解码器校验

大部分原生解码库要求字符串长度必须是 4 的倍数;在解码未填充的 Base64URL 时,必须先用数学公式计算并补足 1 个或 2 个 = 填充符。

八、如何验证 Base64 算法准确性

对规范化后的输入断言 URL-safe 往返等价;覆盖长度模 3 的三种情况、带/不带补位、+ / - _、空串和非法字符,并与标准库结果交叉验证。

九、FAQ

问:为什么 Base64 末尾最多只有 2 个 =?答:因为每 3 个字节一组,多出的字节数只可能是余 1(补 2 个 =)或余 2(补 1 个 =),余 0 则正好整除无 =。

问:为什么 JWT 中的 Base64 不带 =?答:JWT 规范 (RFC 7515) 为了尽量缩短 Header 和 Payload 在 URL/Cookie 传输中的长度,规定必须移除末尾填充符 =

问:Base64 编码后的文本体积增大了多少?答:恰好增大 33.3%(原本 3 字节的二进制数据变成了 4 字节的 ASCII 字符)。

十、总结

理解 Base64 3转4 的 6-bit 切分机制与 = 填充逻辑。在 URL、Cookie 及 JWT 传输场景中,统一使用 RFC 4648 Base64URL 规范防范传输乱码。

来源与延伸阅读

技术审校所依据的规范与权威参考资料。

相关文章

继续阅读

可打开关联的浏览器工具,使用自己的样本验证文中的处理流程。

打开关联工具