使用方法
- 把待还原的网址或转义文本粘进输入框,一行一段。页面打开时已预置三行示例,结果区显示的就是它们的解码结果,不用先点按钮。
- 第 1 行
https%3A%2F%2Fliuquan.net%2Fsearch%3Fq%3D%E5%B7%A5%E5%85%B7%26page%3D2在默认的组件解码模式下还原成完整网址,其中%E5%B7%A5%E5%85%B7变成「工具」;第 3 行a%2Bb%20%E5%B7%A5%E5%85%B7还原成a+b 工具——%2B变加号、%20变空格,二者不会混。 - 如果输入来自 HTML 表单的 GET 提交(地址栏里空格被写成了裸
+),切到「表单解码」模式,工具会先把+换成空格再解码,避免把真正的加号和空格搞混。 - 只想还原中文、不想动
/?&这些结构符时,用「宽松解码」模式:它走decodeURI(),保留字符原样不动,适合整段网址只解文字部分。 - 任何一行出错,工具会指出第几行、哪个
%XX不完整、差什么;全部通过后点「复制结果」即可带走。对照表支持导出 CSV 与 TSV 复制。
这个 URL解码工具能解决什么问题
一是看懂日志和接口里的中文参数。访问日志、回调通知、埋点上报里的中文参数全部是 %E5%B7%A5%E5%85%B7 这种形态,肉眼无法阅读,贴进来立刻还原成原文,排查「用户到底搜了什么」这类问题最直接。
二是定位双重编码。有些系统会把参数编码两次,「你」变成 %25E4%25BD%25A0(15 个字符)——解一次只剩 %E4%BD%A0 还是转义,再解一次才是「你」。本工具会逐行给出结果,看到结果里仍带 % 加两位十六进制,就该怀疑上游编了两次。
三是分清 + 到底是什么。在 application/x-www-form-urlencoded 里 + 表示空格,但在网址组件里它就是一个真加号。同一串 a+b,组件解码得到 a+b,表单解码得到 a b——这是 URL 解码里最经典的歧义,靠模式切换解决,而不是靠猜。
本页不做这些事:不把明文编成转义形式(那是「URL编码」的活)、不解析网址的协议主机路径结构(请用「URL解析器」)、不把百分号转义当 Base64 或十六进制文本处理。反向编码请用页面底部的「URL编码」,按字节核对请用「十六进制转文本转换器」。
解码原理:RFC 3986 百分号转义、UTF-8 多字节与两个内置函数的分工
URL解码工具的核心调用只有两个:逐行跑 decodeURIComponent(s),宽松模式改跑 decodeURI(s)。百分号转义的定义在 RFC 3986 §2.1:% 后跟恰好两个十六进制数字,代表一个字节。所以解码的实质是把字节序列收集起来,再按 UTF-8 重新解释成字符——不是逐个转义孤立地翻字符。
中文为什么要三个转义。「你」的码点是 U+4F60,UTF-8 编码成 3 个字节 E4 BD A0,每个字节各配一个 %,写成 %E4%BD%A0。常用汉字全部落在 U+4E00~U+9FFF 区间,UTF-8 下都是 3 字节,所以一个汉字对应 9 个转义字符:「你好,世界」是 5 个字符 × 3 字节 = 15 字节,写成 45 个字符。emoji 更长:😀 码点 U+1F600,UTF-8 占 4 字节(F0 9F 98 80),对应 12 个字符。
两个内置函数的分工来自保留字符表。RFC 3986 把 : / ? # [ ] @(结构符)和 ! $ & ' ( ) * + , ; =(子分隔符)列为保留字符,另有 71 个 ASCII 字符(26 个大写、26 个小写、10 个数字加 -_.!~*'() 共 9 个符号)完全不编码。decodeURIComponent 会把一切合法转义解到底,包括 %2F → /、%26 → &;decodeURI 则刻意绕开这些结构符——输入 %2F 它原样返回 %2F,只解 %E4%BD%A0 这类非保留部分。整串网址想保住 ? 和 & 的结构就用后者,想彻底还原就用前者。
非法序列会抛 URIError。规则有两条:每个 % 后必须恰好两位十六进制(%ZZ、裸 %、100% 都非法);收集到的字节还必须是合法 UTF-8 序列——%E4%BD 只给了 3 字节汉字「你」的前两个字节,第 3 个字节丢了,decodeURIComponent 直接抛 URIError: URI malformed。本工具捕获这个异常后会说明是哪一种残缺,而不是笼统报错。同理,%C4%E3(「你」的 GBK 字节,只有 2 字节)不是合法 UTF-8,也会报错:GBK 编码的参数本工具解不了,字节数都不同。
+ 为什么不由 decodeURIComponent 处理。把 + 解成空格是表单提交(HTML 规范的 urlencoded 序列化)的约定,不属于 RFC 3986,所以内置函数一律不动 +。表单模式先执行 s.replace(/\+/g, ' ') 再解码,代价是真加号必须已被写成 %2B——正规表单序列化正是这么做的,第 3 行示例 a%2Bb%20%E5%B7%A5%E5%85%B7 就是正确写法。
完整示例(数值仅作演示)
示例条件与页面打开时输入框里的内容完全一致:三行输入,URL解码按默认的「组件解码」模式执行。实测结果:
- 第 1 行
https%3A%2F%2Fliuquan.net%2Fsearch%3Fq%3D%E5%B7%A5%E5%85%B7%26page%3D2,共 64 个字符,含 20 组转义,还原为 https://liuquan.net/search?q=工具&page=2; - 第 2 行
%E4%BD%A0%E5%A5%BD%EF%BC%8C%E4%B8%96%E7%95%8C,45 个字符 = 15 字节 = 5 个字符「你好,世界」,每个汉字或全角逗号各占 9 个转义字符; - 第 3 行
a%2Bb%20%E5%B7%A5%E5%85%B7,21 个字符,还原为 a+b 工具:%2B与%20在组件解码下分别变成加号和空格,互不干扰。
切到「表单解码」再跑一遍,如果输入是裸 + 的 a+b+%E5%B7%A5%E5%85%B7,结果会变成 a b 工具——加号被当成空格;切到「宽松解码」,第 1 行里的 %3A %2F %3F %26 %3D 全部保留原样,只有 %E5%B7%A5%E5%85%B7 变成「工具」。三种模式对同一段输入给出三种口径的结果,这正是选对模式的依据。
常见字符的百分号编码对照表
下表列出最常遇到的保留字符与其编码形式(十进制码点即字节数,单字节字符转义后长度 ×3)。编码方向与解码方向互为逆运算,双向对照都查这张表。
| 字符 | 十进制码点 | 编码形式 | 说明 |
|---|---|---|---|
| 空格 | 32 | %20 | 网址里不允许裸空格;表单序列化里也常写成裸 + |
" | 34 | %22 | 双引号,参数注入防护的第一道关 |
# | 35 | %23 | 锚点分隔符,不编码会被当成页内锚点截断参数 |
% | 37 | %25 | 转义符号自身,双重编码的来源(%25E4 就是再编了一次的 %E4) |
& | 38 | %26 | 参数分隔符,参数值里出现必须编码 |
+ | 43 | %2B | encodeURIComponent 会编码它;裸 + 在表单里是空格 |
/ | 47 | %2F | 路径分隔符;宽松解码模式不还原它 |
: | 58 | %3A | 协议与端口分隔符 |
< | 60 | %3C | 小于号,HTML 上下文里必须编码 |
> | 62 | %3E | 大于号 |
? | 63 | %3F | query 起始符;宽松解码模式不还原它 |
@ | 64 | %40 | 用户信息与主机之间的分隔符 |
[ | 91 | %5B | IPv6 字面量定界符之一 |
] | 93 | %5D | IPv6 字面量定界符之一 |
| 你 | U+4F60(3 字节) | %E4%BD%A0 | 常用汉字一律 9 个字符一组 |
| 😀 | U+1F600(4 字节) | %F0%9F%98%80 | 增补平面字符占 4 字节,共 12 个字符 |
! ' ( ) * - . _ ~ | 33~126 | 不编码 | encodeURIComponent 与 decodeURI 都原样放行的 9 个符号 |
| A–Z a–z 0–9 | 48~122 | 不编码 | 与上面 9 个符号合计 71 个 ASCII 字符保持原样 |
输入范围、边界与精度说明
- 单次输入上限 20 万字符。按 1 个汉字 9 个转义字符折算约能装 2.2 万个汉字的编码,超出这个量级建议按行拆批,浏览器同步解码几百万字符会卡死标签页。
- 转义格式硬校验。每个
%后必须恰好两位 0–9 A–F a–f;工具先用正则定位非法位置再解码,报错带第几行、第几个字符。裸%最常出现在「从日志里复制了一半」的场景。 - UTF-8 序列完整性校验。转义合法不等于能还原:
%E4%BD抛URIError: URI malformed,因为 3 字节序列只收到 2 字节。截断通常发生在按固定长度截取字符串或数据库字段被切掉时。 - 非 UTF-8 编码直接报错而不是出乱码。
decodeURIComponent只按 UTF-8 解释字节,GBK 的%C4%E3会触发异常而非还原成「你」。这类数据先确认来源编码,本工具不猜。 - 大小写不敏感但输出形态保留。
%e4%bd%a0与%E4%BD%A0等价,都能还原成「你」;解码结果里的字符大小写完全由原文字符决定,与转义写法无关。 - 三种模式的边界差异要记牢。组件模式解一切合法转义;表单模式额外把裸
+当空格(真加号须已写成%2B,否则会被误伤);宽松模式保留: / ? # [ ] @与! $ & ' ( ) * + , ; =的转义不解。整串网址用宽松、单个参数值用组件、GET 表单整串用表单。 - 严格按行独立判定。任何一行非法,整次解码不输出结果并说明该行问题,不会给你「前两行对、第三行悄悄错」的混合输出——混合输出在排查时比报错更误事。
常见问题
解出来的内容里还是 %E4 这样的转义,怎么办?
这是典型的双重编码:原文被编码了两次,「你」先变成 %E4%BD%A0,再编码一次就成了 %25E4%25BD%25A0(% 自身被编成 %25)。解一次只剩转义形式,再解一次才是汉字。本工具每次只解一层,看到结果仍带 %XX 就再点一次。
地址栏里的 + 解出来还是加号,不是空格?
内置函数按 RFC 3986 办事,不认表单的 + 约定。来自 GET 表单的整串参数请切「表单解码」模式,工具会先把裸 + 换成空格;反之,真加号必须在上游写成 %2B,两种写法在正规序列化里不会混用。
宽松模式和组件模式结果不一样,哪个是对的?
都对,口径不同。宽松模式(decodeURI)保留 %2F %3F %26 %3D 等结构符的转义,适合只想把中文还原、保住网址结构;组件模式(decodeURIComponent)解到底,适合处理单个参数值。把整串网址用组件模式解完,?q= 的 ? 和 = 若原本被编码过也会被还原,结构可能就变了。
报 URIError: URI malformed,最可能是什么原因?
两类:转义写法不完整,如 %ZZ 或落单的 %;UTF-8 多字节序列被截断,如 %E4%BD 只有三字节汉字的前两字节。常见于日志被截断、字符串按固定长度切割、复制时漏了几位。报错信息会指出第几行,配合对照表核对字节。
GBK 编码的参数能解吗?
不能直接解。「你」的 GBK 是 2 字节 C4 E3,不是合法 UTF-8 序列,decodeURIComponent 会抛错而不是给出错字。这是刻意设计:强行解释只会产出更难排查的假乱码。先确认上游编码,把字节拿给「十六进制转文本转换器」按对应编码核对。
为什么一个中文占 9 个转义字符,比原文长这么多?
转义的最小单位是 1 个字节,UTF-8 里常用汉字占 3 字节,每字节写成 %XX 共 3 个字符,3×3=9。「你好,世界」5 个字符、15 字节、45 个字符,膨胀到原文的 9 倍;纯 ASCII 则是 1 字节对 3 字符,膨胀 3 倍。这也是网址长度限制对中文参数格外苛刻的原因。
解码结果里的中文显示成方块或问号是坏了吗?
不是数据坏了,是显示环节的问题。解码产出的是标准 Unicode 文本,网页按 UTF-8 显示正常;粘进按 GBK 显示的终端或旧软件才会变成问号。把结果复制到任何 UTF-8 编辑器里即可看到原文,原始转义串没有丢失。
输入的内容会被上传或保存吗?
不会。转义还原、+ 号替换、错误定位全部在页面里用浏览器内置函数完成,没有任何网络请求,也不写入浏览器存储。想自行验证,打开开发者工具的 Network 面板,多点几次「开始解码」,可以看到没有新请求发出。
相关工具
- URL编码:本页的逆操作,把明文按 encodeURIComponent 规则编成 %XX 形式,两头对照最直观。
- URL解析器:把整条网址拆成协议、主机、路径、query 各段,先拆段再逐段解码更不容易出错。
- Base64解码:同样是「还原乱码」场景,Base64 处理的是 4 比 3 的字节重排,与百分号转义是两套体系。
- HTML实体解码:
人与&的还原,网页源码里的另一类转义。 - Unicode转义反转义工具:处理
\u4f60写法,JS 字符串里常见,与 URL 转义路径不同。 - 十六进制转文本转换器:当本页报 UTF-8 截断错误时,把字节粘到那边逐字节核对最方便。
- 编码解码:查看全部编码解码工具。