Base64 解码

把每行一段 Base64 文本还原成字节,再按 UTF-8 解释成可读文字;顺带告诉你填充缺了几个、长度为什么非法、这段内容到底是不是文本。

[1] 你好,世界
     hex: E4 BD A0 E5 A5 BD EF BC 8C E4 B8 96 E7 95 8C
[2] Hello, World!
     hex: 48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21
[3] 非文本内容:解码出 8 字节,其中含无法按 UTF-8 解释的字节。十六进制 89 50 4E 47 0D 0A 1A 0A;这是图片、压缩包或密文一类的二进制数据,不是可读文本。

提示:输入框里按 Ctrl + Enter(macOS 用 Cmd + Enter)立刻解码一次;Enter 留给换行,因为这里一行就是一段独立的 Base64。文本框为空时不会自动填示例,点「载入示例」可以随时还原上面那三行。

使用方法

  1. 把要还原的 Base64 文本粘进上面的输入框,一行一个字符串。页面打开时框里已经预置了三行示例,结果区显示的就是它们的解码结果,不需要先点按钮。
  2. 第一行 5L2g5aW977yM5LiW55WM 共 20 个字符,还原出来是 你好,世界,对应 15 个字节;第三行 iVBORw0KGgo= 只有 12 个字符,还原出的 8 个字节是 PNG 文件头,属于非文本内容。
  3. 字符串如果来自网址参数或令牌,字母表里会出现 - 和 _ 而不是 + 和 /,把「接受 URL-safe 字母表」勾上即可,不必手工替换字符。
  4. 末尾的 = 被系统吃掉时不用管,工具会自己补上并在结果里写明补了几个;如果补齐之后长度仍然不合法,会直接指出是第几行、差在哪里、余数是多少。
  5. 要核对 PNG、压缩包一类的二进制内容,勾选「同时显示十六进制字节」,每个文本行下面会多出一行 hex。全部处理完点「复制结果」把整段带走。

这个 Base64 解码工具能解决什么问题

一是把接口返回值里的 Base64 还原成人能读的文字。日志、埋点上报、Webhook 回调经常把正文塞进一个 Base64 字段,肉眼完全看不出来,贴进来就能看到原文,顺便确认后端用的到底是不是 UTF-8。

二是定位中文乱码究竟出在哪一步。同一串 Base64,有的页面显示正常,有的显示成 ä½ 这种字符,差别通常不在 Base64 本身,而在最后一步用 Latin-1 还是 UTF-8 去解释那些字节。这个 Base64 解码工具会把解释前的字节和十六进制一并列出来,一眼分清是字节取错了还是解释方式选错了。

三是判断一段 Base64 里装的到底是不是文本。图片、压缩包、加密结果都能被 Base64 表示,它们在解码后并不是合法的 UTF-8 序列。本工具不会硬转成问号,而是明确写出「非文本内容」并给出字节数与十六进制前缀。四是排查填充与长度问题:有些系统在拼接、截断或写库时会把末尾的 = 弄丢,工具按行报告缺几个填充、整串长度是否合法,而不是笼统回一句「格式错误」。

本页不做这些事:不把文本重新变成 Base64、不解析令牌的头部与载荷字段、不把 Base64 还原成图片或压缩包文件。要拆令牌请用页面底部的「JWT解码」,要做字节与文本互转请用「十六进制转文本转换器」。

解码原理:RFC 4648 字母表、4 比 3 的字节关系与填充规则

这个 Base64 解码工具的核心只有三步:atob(s) 把 Base64 文本还原成二进制字符串,Uint8Array.from(atob(s), c => c.charCodeAt(0)) 把它变成真正的字节数组,再用 new TextDecoder('utf-8', { fatal: true }).decode(bytes) 解释成文字。三步缺一步都会出错,而多数在线工具只做第一步就塞进页面,所以中文一律是乱码——差别不在字符表,在后面两步。

每 4 个字符换 3 个字节,这是骨架。RFC 4648 定义的字母表是 A–Z、a–z、0–9、+、/ 共 64 个符号,每个代表 6 位;4 个符号正好 24 位,也正好切成 3 个字节。以最短的 YQ== 为例,Y 的值是 24(011000),Q 是 16(010000),两个 = 按 0 处理,拼起来是 011000 010000 000000 000000,展开成 0x61 0x00 0x00,只取有效字节数(3 减 2 个填充,等于 1),得到 0x61,也就是小写字母 a。

填充 = 的个数决定这一组还原出几个字节。出现 1 个 =,末组只剩 2 个有效字节,例如 YWI= 还原成 ab;出现 2 个 =,末组只剩 1 个,例如 YQ== 还原成 a;一个都没有,说明这一组是完整的 3 字节,例如 YWJj 还原成 abc。正因如此,合法的 Base64 去掉尾部填充后长度除以 4 只可能余 0、2、3,余 1 在数学上不可能出现——一旦算出余 1,一定是字符多了或少了。

中文乱码的根源在第一步的返回值类型上。按 HTML 标准,atob() 返回的是每个字符码点都落在 0 到 255 之间的字符串,等价于 Latin-1,它并不知道原始数据是什么编码。把 5L2g 交给它,拿到的是码点 U+00E4、U+00BD、U+00A0 三个字符,直接显示就是 ä½ ;而这三个码点对应的真实字节 E4 BD A0 按 UTF-8 解释才是「你」。早年用 decodeURIComponent(escape(atob(s))) 就是在补这一步,但 escape 早已从标准中删除,还会把码点大于 255 的字符算错,现在应当改用 TextDecoder。

为什么要带 fatal: true。TextDecoder 默认遇到非法字节会悄悄换成 U+FFFD(一个「�」),你会拿到一段看着正常、实际已被破坏的文字;加上这个选项后,非法序列直接抛异常,工具就能据此判定「非文本内容」,而不是丢给你一串问号。

字母表方面,RFC 4648 定义了两套:§4 的标准表第 62、63 号符号是 + 和 /;§5 的网址安全表把它们换成 - 和 _,其余 62 个完全一致。两套表没有版本号也没有自动识别机制,含 - 的串落在标准解码器眼里就是非法字符。另据 §3.3,解码时允许忽略换行与空白,所以折行的 Base64 可以直接贴。体积上则固定膨胀 4/3,也就是 33.3%:1 MiB(1048576 字节)的原文编码后分成 349526 组、共 1398104 个字符,1024 字节则是 1368 个字符。

完整示例(数值仅作演示)

示例条件与页面打开时输入框里的内容完全一致:三行 Base64,不勾选「接受 URL-safe 字母表」,勾选「同时显示十六进制字节」。三行实测结果是:

三行共 52 个字符(其中 3 个是填充),解码后 36 字节。横着算是 15 + 13 + 8 = 36;竖着算,13 组每组最多 3 字节、上限 39,减去 3 个填充各带走 1 字节,同样是 36,两个方向对得上。第 1 行的 15 字节还值得单独拆一遍:「你好,世界」是 5 个字符——四个汉字加一个全角逗号,UTF-8 下每个占 3 字节,所以 6 + 3 + 6 = 15,而 15 ÷ 3 × 4 = 20 正好等于输入串的长度。这就是判断一段 Base64 有没有被截断的最快办法。

输入片段与解码结果对照表

下表覆盖了本工具最常见的几类输入。注意「解码字节数」一列才是真相,字符数只说明它写得多长;同一个字符数可以对应完全不同的字节数。

输入片段字符数末尾填充解码字节数还原结果与说明
YQ==42 个 =1还原成 a(0x61),最短的完整一组
YWI=41 个 =2还原成 ab,末组只剩 2 个有效字节
YWJj4无3还原成 abc,一组整除 3 字节
YWJjZA==82 个 =4还原成 abcd,两组共 4 字节
5L2g4无3一个汉字「你」,UTF-8 下正好 3 字节一组
5L2g5aW98无6还原成「你好」,两个汉字
5L2g5aW977yM5LiW55WM20无15还原成「你好,世界」,本页示例的第 1 行
44GT44KT44Gr44Gh44Gv20无15日文「こんにちは」,每个假名同样是 3 字节
SGVsbG8sIFdvcmxkIQ==202 个 =13纯 ASCII,还原成 Hello, World!
8J+YgA==82 个 =4一个表情符号,UTF-8 下占 4 字节
iVBORw0KGgo=121 个 =8PNG 文件头,属非文本内容
AAECAwQFBgc=121 个 =8字节 00 到 07,全是控制符,同样判为非文本
5LiA4无3还原成一个汉字「一」,与「你」同为 3 字节
//8=41 个 =2字节 FF FF,不是合法的 UTF-8 起始序列
YWJjZA6缺 2 个4长度不是 4 的倍数,工具自动补齐成 YWJjZA==
YQ2缺 2 个1同样自动补齐成 YQ==,还原成 a

输入范围、边界与精度说明

常见问题

解出来的中文是「ä½ 」这种字符,是数据坏了吗?

多半不是坏,而是解释方式错了。这三个字符的码点是 U+00E4、U+00BD、U+00A0,正好等于字节 E4 BD A0,按 UTF-8 解释就是「你」。出现这种现象说明那段代码把 atob() 的返回值直接当文字显示了,中间少了「取字节再按 UTF-8 解码」这一步。

末尾的 = 被弄丢了,还能解码吗?

能。缺 1 个或 2 个填充很常见,工具会自动补齐并注明补了几个。但「缺填充」和「长度非法」是两回事:YWJjZA 补上就正常,而长度除以 4 余 1 的串无论补多少都救不回来,只能回去核对原文。

提示「非文本内容」,是不是数据坏了?

不是。这个提示只说明解码出的字节不是合法 UTF-8 序列,并不代表内容有问题,图片、压缩包、PDF、密文在 Base64 里都很常见。工具会给出字节数与十六进制前缀,例如 89 50 4E 47 开头就是 PNG。

提示某行长度余 1,该怎么改?

余 1 说明字符总数不对,最常见的原因是复制时少了字符,或者中间混进了不可见字符。先去掉空白再数个位数,确认是 4 的倍数;如果末尾有 =,先去 = 再数。

串里带 - 和 _ 怎么办?

勾上「接受 URL-safe 字母表」。RFC 4648 §5 规定把 + 换成 -、/ 换成 _,其余 62 个符号不变,结果可以直接放进网址路径和文件名。两套表没有自动识别机制,必须由你告诉工具用的是哪一套。

Base64 能当加密用吗?

不能,它只是一种编码。任何拿到这串字符的人都能立刻还原出原文,本页做的就是这件事。把敏感字段做一次 Base64 就以为别人看不见是很典型的误用,要保密必须用真正的加密算法,并且密钥不能和密文放在一起。

为什么解出来的内容比预期短很多?

先数输入长度。Base64 是 4 个字符换 3 个字节,20 个字符最多 15 字节,UTF-8 下只够放 5 个汉字或 5 个全角标点;反过来纯 ASCII 是 1 字节 1 个字符,13 个字节就能装下整个 Hello, World!。中英混排时凭肉眼估长度几乎一定估错。

我输入的内容会被上传或保存吗?

不会。字符表还原、填充补齐、UTF-8 解释全部在页面里完成,没有任何网络请求,也不会写入浏览器存储。想自己确认,打开开发者工具的 Network 面板,连点几次「开始解码」,可以看到没有新请求发出。

相关工具