JavaScript 里的 Base64:btoa 与中文乱码
btoa 只接受 Latin-1 字符,中文码点超过 255 就直接抛 InvalidCharacterError。正确做法是先用 TextEncoder 编成 UTF-8 字节,再逐字节转成字符串喂给 btoa;解码反过来做。
粘贴即自动处理,不用点按钮(Ctrl+Enter 立刻转换 / Esc 清空)
拖文件进来,或 ——截图直接 Ctrl+V 也行
任意类型 · 100 MB 封顶
粘贴、拖拽、Ctrl+V 截图都行
最基础的两个 API
btoa('hello') // "aGVsbG8="
atob('aGVsbG8=') // "hello"这两行只在内容是纯 ASCII 时成立。一旦出现中文、emoji、日文,下面这个问题就来了。
中文为什么一定报错
btoa 要求输入里每个字符都落在 0–255,中文码点远大于这个范围,于是直接抛 InvalidCharacterError。正确写法是先转字节再编码:
function b64encode(str) {
const bytes = new TextEncoder().encode(str) // 先编成 UTF-8 字节
let bin = ''
for (const b of bytes) bin += String.fromCharCode(b)
return btoa(bin)
}解码反过来:atob 拿到字节串,再用 TextDecoder 还原成文本。不要写 String.fromCharCode(...bytes),大文件一次展开会爆栈,上面用循环就是为了避开它。
Node 里写法不一样
Buffer.from(str).toString('base64') // 编码
Buffer.from(b64, 'base64').toString('utf8') // 解码
Buffer.from(b64, 'base64url') // 处理 -_ 与缺失的填充Node 直接吃 Buffer,不需要 TextEncoder 那一套;反过来把这段抄进浏览器,会报 Buffer is not defined。
base64url:前端最常踩的变体
JWT 和 URL 参数里的 Base64 会把 + 换成 -、/ 换成 _,并去掉结尾的 =。直接丢给 atob 会解不出来或出来一串乱码。
处理只需两步:把 - _ 换回 + /,再按 4 的倍数补上 =。
常见问题
btoa 和 Base64 是一回事吗?
btoa 是浏览器提供的一个函数,做的正是 Base64 编码;它只处理 Latin-1,所以中文要自己先转字节。
大文件怎么处理?
别一次性读成字符串。用 FileReader.readAsDataURL 或分块读再拼接;几十 MB 以上交给后端或命令行更合适。
解出来是乱码?
两个常见原因:拿到的是 base64url(要换字符补填充),或者原始内容本来就不是 UTF-8。