atob 和 btoa 仅支持 ASCII 字符,处理中文会报错;需用 TextEncoder/TextDecoder 封装 utf8_to_b64/b64_to_utf8;Base64 非加密,敏感数据不可依赖其保密。

atob 和 btoa 只能处理 ASCII 字符串,中文会直接报错
atob 和 btoa 是浏览器原生 API,但它们不支持 UTF-8 编码的字符串。一旦传入含中文、emoji 或任意非 ASCII 字符的字符串,btoa 会抛出 DOMException: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.
这是因为 btoa 内部把字符串按 Latin-1(即单字节)编码后转 Base64,而 JavaScript 字符串是 UTF-16。中文字符在 UTF-16 中占两个字节,直接喂给 btoa 就越界了。
实操建议:
- 若数据确定为纯英文、数字、ASCII 符号(如 token、base64-encoded binary ID),可直接用
btoa("hello")→"aGVsbG8=" - 若含中文或不确定编码,必须先手动转成 UTF-8 字节数组,再用
btoa编码;解码时反向操作——不能跳过这步 - 推荐封装两个安全函数:
utf8_to_b64和b64_to_utf8,内部用TextEncoder/TextDecoder
在 fetch 请求头中用 btoa 实现 Basic Auth 认证
HTTP Basic Auth 要求请求头 Authorization: Basic <base64></base64>,其中 base64 是 username:password 拼接后编码的结果。这里只要用户名密码本身不含 Unicode 字符,就可直接用 btoa。
示例:
const username = "admin";
const password = "p@ssw0rd";
const authStr = `${username}:${password}`;
const encoded = btoa(authStr); // "YWRtaW46cEBzc3cwcmQ="
fetch("/api/data", {
headers: {
Authorization: `Basic ${encoded}`
}
});
注意点:
- 不要对整个
Basic xxx做二次编码,只编码username:password部分 - 如果密码含冒号(
:)或非 ASCII 字符,btoa仍会失败,此时应改用服务端颁发的 bearer token - 前端硬编码凭证极不安全,仅限调试或内网可信环境
异步请求返回 base64 字符串时,用 atob 解码需先校验格式
有些接口(如上传预签名 URL 返回、某些文件元数据接口)会直接返回 Base64 字符串。调用 atob 前必须确保字符串是合法 Base64 格式,否则会抛出 InvalidCharacterError。
常见错误现象:
- 后端返回的 base64 带前缀如
data:text/plain;base64,SGVsbG8=,直接传给atob会失败 - 字符串含空格、换行、URL-safe 变体(用
-和_替代+和/)
实操建议:
- 先用正则粗筛:
/^[A-Za-z0-9+/]*={0,2}$/.test(str),再 trim 空格 - 提取 data URL 中的 base64 部分:
str.split(",")[1](前提是确认是 data URL) - URL-safe base64 需先替换:
str.replaceAll("-", "+").replaceAll("_", "/"),再补足等号(长度需为 4 的倍数)
Base64 不是加密,敏感数据不能靠它“掩护”
btoa 和 atob 是编码/解码,不是加密。任何拿到 base64 字符串的人都能瞬间还原原始内容——只需一行 atob("...")。
在异步请求中误用的典型场景:
- 把用户手机号、邮箱用
btoa“混淆”后发到接口,以为增加了安全性 - 前端 localStorage 存
btoa(JSON.stringify(obj)),当作“轻量加密”
这类做法毫无防护价值。真正需要保密的数据,必须由后端生成加密 token 或使用 TLS + 后端鉴权,前端只负责透传。
容易被忽略的是:即使你用了 TextEncoder + btoa 安全地编码了中文,它依然只是可逆编码。别把它和 Crypto.subtle.encrypt 混为一谈。

















