功能说明
该示例实现 base64url 的编码与解码。base64url 把标准 Base64 中的加号与斜杠替换为连字符与下划线,并去掉末尾填充,因此可以安全地放进 URL、Cookie 和 JWT 片段。编码支持字符串与 Uint8Array,解码默认按 UTF-8 严格模式还原文本。
关键代码
encodeBase64Url 先把输入统一为字节,再逐字节拼成二进制字符串交给 btoa,最后替换字符并去掉等号。decodeBase64Url 先校验字符集与长度,长度除以 4 余 1 一定是非法输入;随后补回等号、还原字符集并用 atob 得到二进制串,再通过 Uint8Array.from 与 TextDecoder 解码。TextDecoder 的 fatal 选项会把非法 UTF-8 直接抛错,而不是悄悄替换成问号。
使用注意
btoa 与 atob 在浏览器和较新的 Node 中都可用,但如果运行环境缺失需要自行提供实现。编码二进制数据后解码为文本可能得到乱码,应改为返回字节数组。base64url 不是加密,也不能防篡改,JWT 的完整性必须依赖签名校验。解码前仍应限制输入长度,避免超大字符串占用内存。
验证方式
对 user:42 编码得到 dXNlcjo0Mg,再解码断言还原原文。测试中文与表情符号的往返,确认 UTF-8 未被破坏。传入包含加号、斜杠或空格的字符串断言抛错,长度为 1 的输入也抛错。最后用非法 UTF-8 字节序列断言解码抛错。
代码示例
export function encodeBase64Url(input) {
const bytes = toBytes(input);
let binary = "";
for (const byte of bytes) binary += String.fromCharCode(byte);
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
export function decodeBase64Url(input, options = {}) {
if (typeof input !== "string") throw new TypeError("input must be a string");
if (!/^[A-Za-z0-9_-]*$/.test(input)) throw new Error("input contains invalid base64url characters");
if (input.length % 4 === 1) throw new Error("input has an invalid base64url length");
const { encoding = "utf-8" } = options;
const padded =
input.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - (input.length % 4)) % 4);
const binary = atob(padded);
const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
return new TextDecoder(encoding, { fatal: true }).decode(bytes);
}
function toBytes(input) {
if (typeof input === "string") return new TextEncoder().encode(input);
if (input instanceof Uint8Array) return input;
throw new TypeError("input must be a string or Uint8Array");
}
const token = encodeBase64Url("user:42");
console.log(token);
console.log(decodeBase64Url(token));
console.log(encodeBase64Url(new Uint8Array([251, 255, 190])));