btoa() 无法直接编码中文,因其仅支持 Latin-1 字符(码点 0–255);正确做法是先 encodeURIComponent 转为 ASCII 百分号编码,再用 btoa 编码为 Base64,解码时须严格按 decodeURIComponent(atob(encodedStr)) 顺序执行。
btoa() 编码中文会报错浏览器原生的 btoa() 只接受 Latin-1(即单字节,码点 0–255)范围内的字符。一旦传入中文、emoji 或其他 Unicode 字符,就会抛出 DOMException: The string to be encoded contains characters outside of the Latin1 range。
这不是“偶尔乱码”,而是根本无法执行——函数直接中断。所以不能靠试错,必须前置处理。
btoa("你好") → 立即报错btoa("hello") 正常,btoa("héllo") 也失败(带重音符的 é 是 Unicode 字符)btoa() 内部把字符串当字节数组处理,而 JavaScript 字符串是 UTF-16 编码,二者不匹配encodeURIComponent,再 btoa
把中文转成百分号编码(如 "你好" → "%E4%BD%A0%E5%A5%BD"),得到的全是 ASCII 字符,btoa() 就能安全接手。
注意:不能只用 encodeURIComponent 单独传输,因为它的输出不是 Base64 格式,某些协议(如 HTTP Basic Auth、JWT payload)明确要求 Base64 编码。
btoa(encodeURIComponent(str))
btoa(encodeURIComponent("你好")) → "JUU0JUJEJUEwJUU1JUFEJUE3"
escape():已废弃,对部分字符(如 +、/)处理不一致,容易出错atob,再 decodeURIComponent
atob() 解出来的是一串原始字节对应的字符串(比如 "u00e4u00bdu00a0" 这种形式),它还不是可读中文,必须用 decodeURIComponent() 把百分号编码还原回来。
decodeURIComponent(atob(encodedStr))
decodeURIComponent 再 atob),会因格式不匹配而报错或返回空字符串.trim()
这套组合方案在现代浏览器中稳定,但有隐含成本:每次编解码都涉及两次字符串转换(URI 编码 + Base64 转换),对长文本(如 >100KB 的 JSON)会产生明显延迟。
Buffer.from(str, 'utf8').toString('base64'),更直接;前端可考虑 TextEncoder + Uint8Array + 自定义 Base64 表,但实现复杂encodeURIComponent/atob/btoa
+、/、= 在 URL 中有特殊含义,若用于 URL 参数,需额外做 replace(/+/g, '-').replace(///g, '_').replace(/=/g, '')(URL-safe Base64)