Skip to content
encode2026-07-253 分钟阅读

很多开发者在第一次用 Base64 编码中文时都会遇到同一个问题:编码后再解码,中文变成了乱码。比如把"你好世界"编码后解码回来,得到的却是一堆 㽠好 之类的字符。

这不是 Base64 算法本身的 bug,而是字符编码在作怪。本文帮你彻底搞清楚 base64 中文乱码的根因,并给出正确的处理方式。

为什么 Base64 编码中文会乱码

Base64 本质上是一种二进制到文本的编码方案,它处理的是字节(bytes),不是字符。问题出在"字符 → 字节"这一步:

  • UTF-8 中,一个中文字符占 3 个字节
  • GBK 中,一个中文字符占 2 个字节

如果编码时用 UTF-8 把中文转成字节流,解码时却用 GBK 去还原,字节数对不上,自然就乱码了。

一个典型的错误场景:

// 错误示范:直接用 btoa 编码中文
btoa("你好世界");
// Uncaught DOMException: The string to be encoded contains characters outside of the Latin1 range.

浏览器的 btoa() 只支持 Latin1 字符(U+0000 到 U+00FF),遇到中文直接报错。有些人会用 escape() 绕过:

// 能跑,但有隐患
btoa(escape("你好世界"));
// 解码时必须配合 unescape(),否则就是乱码
atob(btoa(escape("你好世界"))); // 得到的是 escape 编码,不是原文
unescape(atob(btoa(escape("你好世界")))); // 这才能还原

这种方式虽然能工作,但 escape() 已被废弃,而且跨平台传输时如果对方不知道要 unescape,解码结果就是乱码。

正确的 Base64 中文编解码方法

核心原则:先把字符串按 UTF-8 转成字节数组,再做 Base64 编码;解码时反过来。

方法一:使用 TextEncoder / TextDecoder(推荐)

function base64EncodeUnicode(str) {
  const bytes = new TextEncoder().encode(str); // 字符串 → UTF-8 字节
  const binary = Array.from(bytes, b => String.fromCharCode(b)).join("");
  return btoa(binary);
}

function base64DecodeUnicode(base64) {
  const binary = atob(base64);
  const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
  return new TextDecoder().decode(bytes); // UTF-8 字节 → 字符串
}

// 测试
const encoded = base64EncodeUnicode("你好世界,Hello!");
console.log(encoded); // "5L2g5aW95LiW55WM77yMSGVsbG8h"

const decoded = base64DecodeUnicode(encoded);
console.log(decoded); // "你好世界,Hello!"

方法二:Node.js 环境

// 编码
const encoded = Buffer.from("你好世界", "utf-8").toString("base64");
console.log(encoded); // "5L2g5aW95LiW55WM"

// 解码 —— 注意必须指定 utf-8
const decoded = Buffer.from(encoded, "base64").toString("utf-8");
console.log(decoded); // "你好世界"

// 乱码的根源:编码和解码用了不同的字符集
const wrongDecode = Buffer.from(encoded, "base64").toString("latin1");
console.log(wrongDecode); // "ä½ å¥½ä¸ç" ← 这就是你看到的乱码

方法三:处理已有的 GBK 编码数据

如果你的数据源是 GBK 编码(常见于老系统、Windows 中文环境),需要先转成 UTF-8:

// 浏览器端可以用 TextDecoder 指定编码
const gbkBytes = new Uint8Array([0xC4, 0xE3, 0xBA, 0xC3]); // "你好" 的 GBK 编码
const text = new TextDecoder("gbk").decode(gbkBytes);
console.log(text); // "你好"

// 然后再用标准方法做 Base64
const base64 = base64EncodeUnicode(text);

避免乱码的实用建议

  1. 全链路统一 UTF-8:从数据库、后端接口到前端,全部使用 UTF-8 编码,从根源上避免编码不一致。

  2. 传输时标注编码:如果必须处理多编码数据,在协议或文件头中明确标注字符集(如 Content-Type: text/plain; charset=utf-8)。

  3. 不要混用编码函数btoa/atob 只处理 Latin1,处理中文务必走 UTF-8 字节转换。

  4. 本地处理更安全:Base64 编解码虽然不涉及加密,但如果内容包含敏感信息(如用户数据、内部接口参数),建议使用本地工具处理,避免数据经过第三方服务器。

如果你只是需要快速编解码一段中文文本,可以直接使用我们的 Base64 编解码工具,所有计算都在浏览器本地完成,数据不会上传到任何服务器,粘贴即转换,支持 UTF-8 中文,不会出现乱码问题。


ad