使用方法
- 把要还原的 Base64 文本粘进上面的输入框,一行一个字符串。页面打开时框里已经预置了三行示例,结果区显示的就是它们的解码结果,不需要先点按钮。
- 第一行
5L2g5aW977yM5LiW55WM共 20 个字符,还原出来是 你好,世界,对应 15 个字节;第三行iVBORw0KGgo=只有 12 个字符,还原出的 8 个字节是 PNG 文件头,属于非文本内容。 - 字符串如果来自网址参数或令牌,字母表里会出现
-和_而不是+和/,把「接受 URL-safe 字母表」勾上即可,不必手工替换字符。 - 末尾的
=被系统吃掉时不用管,工具会自己补上并在结果里写明补了几个;如果补齐之后长度仍然不合法,会直接指出是第几行、差在哪里、余数是多少。 - 要核对 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 字母表」,勾选「同时显示十六进制字节」。三行实测结果是:
- 第 1 行
5L2g5aW977yM5LiW55WM:20 个字符、0 个填充,还原出 15 字节,按 UTF-8 是你好,世界,十六进制为E4 BD A0 E5 A5 BD EF BC 8C E4 B8 96 E7 95 8C; - 第 2 行
SGVsbG8sIFdvcmxkIQ==:20 个字符、2 个填充,还原出 13 字节,就是 Hello, World!; - 第 3 行
iVBORw0KGgo=:12 个字符、1 个填充,还原出 8 字节,十六进制为89 50 4E 47 0D 0A 1A 0A,正是 PNG 固定不变的 8 字节文件头,所以判为非文本内容。
三行共 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== | 4 | 2 个 = | 1 | 还原成 a(0x61),最短的完整一组 |
YWI= | 4 | 1 个 = | 2 | 还原成 ab,末组只剩 2 个有效字节 |
YWJj | 4 | 无 | 3 | 还原成 abc,一组整除 3 字节 |
YWJjZA== | 8 | 2 个 = | 4 | 还原成 abcd,两组共 4 字节 |
5L2g | 4 | 无 | 3 | 一个汉字「你」,UTF-8 下正好 3 字节一组 |
5L2g5aW9 | 8 | 无 | 6 | 还原成「你好」,两个汉字 |
5L2g5aW977yM5LiW55WM | 20 | 无 | 15 | 还原成「你好,世界」,本页示例的第 1 行 |
44GT44KT44Gr44Gh44Gv | 20 | 无 | 15 | 日文「こんにちは」,每个假名同样是 3 字节 |
SGVsbG8sIFdvcmxkIQ== | 20 | 2 个 = | 13 | 纯 ASCII,还原成 Hello, World! |
8J+YgA== | 8 | 2 个 = | 4 | 一个表情符号,UTF-8 下占 4 字节 |
iVBORw0KGgo= | 12 | 1 个 = | 8 | PNG 文件头,属非文本内容 |
AAECAwQFBgc= | 12 | 1 个 = | 8 | 字节 00 到 07,全是控制符,同样判为非文本 |
5LiA | 4 | 无 | 3 | 还原成一个汉字「一」,与「你」同为 3 字节 |
//8= | 4 | 1 个 = | 2 | 字节 FF FF,不是合法的 UTF-8 起始序列 |
YWJjZA | 6 | 缺 2 个 | 4 | 长度不是 4 的倍数,工具自动补齐成 YWJjZA== |
YQ | 2 | 缺 2 个 | 1 | 同样自动补齐成 YQ==,还原成 a |
输入范围、边界与精度说明
- 合法长度一定是 4 的倍数。去掉尾部填充后长度除以 4 只可能余 0、2、3;余 1 时任何解码器都还原不出来,本工具会指出是第几行、实际长度多少、余数多少,而不会只说一句「格式错误」。
- 字符集只认 64 个符号加填充。报错会带上第几行、第几个字符、那个字符本身。最常见的两种失误:把网址里
%2B形式的加号没还原就贴进来;把带-和_的网址安全字母表当成标准表直接解。 - 填充
=只能出现在末尾且最多 2 个。缺填充可以自动补齐,多出来的填充不能自动截掉——那意味着前面的内容也可能被改动过,宁可报错也不猜。 - 单次输入上限 20 万字符,按 4/3 的膨胀率倒推只代表约 15 万字节的原始数据。再往上浏览器解码会明显变卡,建议按行拆批贴。
- 非 UTF-8 二进制一律判为非文本。工具用
fatal: true让非法序列直接抛错,再列出字节数与完整十六进制。这是刻意设计:8 个字节的 PNG 文件头若硬按 UTF-8 转,会得到替换字符加一堆控制符,比直接标明「非文本」更难读。 - 空白一律忽略。依据 RFC 4648 §3.3,解码时允许跳过换行与空格,工具在判断长度前会先把空白全部删掉,所以「粘贴时多带了几个换行」不会导致失败。
- 严格区分大小写,并且按行独立判定。
YQ==还原成小写字母a,把开头换成小写的yQ==就变成字节C9 00,取第一个字节是0xC9。只要有一行不合法,整次解码就不输出结果并说清那一行的问题,不会给你一份「前两行对、第三行悄悄错了」的混合输出。
常见问题
解出来的中文是「ä½ 」这种字符,是数据坏了吗?
多半不是坏,而是解释方式错了。这三个字符的码点是 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 面板,连点几次「开始解码」,可以看到没有新请求发出。
相关工具
- Base32解码:同一族编码,字母表只有 32 个符号、每组 8 个字符换 5 字节,常用于一次性密钥。
- URL解码:把
%E4%BD%A0这类百分号转义还原成文字,和本页的区别是它不做字节重排。 - HTML实体解码:把
人、&这类实体还原成原字符,处理网页源码时用得上。 - JWT解码:令牌也是 Base64,但它把三段拼在一起还要做签名校验,单独用本页拆容易看错分段。
- 十六进制转文本转换器:当本页给出
E4 BD A0这样的字节时,拿到那边可以单独核对每个字节对应的字符。 - 二进制转文本:把
01000001这种 0 和 1 的序列还原成文字,比十六进制更底层一层。 - Unicode转义反转义工具:处理
\u4f60这类转义写法,和 Base64 是两条完全不同的表示路径。 - 编码解码:查看全部编码解码工具。