URL解码

把 %E4%BD%A0 这类百分号转义还原成「你」这样的原文。三种解码模式覆盖网址组件、表单参数和宽松整串,出错时告诉你第几行、哪个转义不完整,而不是只丢一句「格式错误」。

[1] https://liuquan.net/search?q=工具&page=2
[2] 你好,世界
[3] a+b 工具

提示:输入框里按 Ctrl + Enter(macOS 用 Cmd + Enter)立即解码一次;Enter 留给换行,这里一行就是一段独立的待解码文本。示例已预置在输入框内并直接出结果,点「载入示例」可随时还原。

使用方法

  1. 把待还原的网址或转义文本粘进输入框,一行一段。页面打开时已预置三行示例,结果区显示的就是它们的解码结果,不用先点按钮。
  2. 第 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 变空格,二者不会混。
  3. 如果输入来自 HTML 表单的 GET 提交(地址栏里空格被写成了裸 +),切到「表单解码」模式,工具会先把 + 换成空格再解码,避免把真正的加号和空格搞混。
  4. 只想还原中文、不想动 / ? & 这些结构符时,用「宽松解码」模式:它走 decodeURI(),保留字符原样不动,适合整段网址只解文字部分。
  5. 任何一行出错,工具会指出第几行、哪个 %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解码按默认的「组件解码」模式执行。实测结果:

切到「表单解码」再跑一遍,如果输入是裸 + 的 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%2BencodeURIComponent 会编码它;裸 + 在表单里是空格
/47%2F路径分隔符;宽松解码模式不还原它
:58%3A协议与端口分隔符
<60%3C小于号,HTML 上下文里必须编码
>62%3E大于号
?63%3Fquery 起始符;宽松解码模式不还原它
@64%40用户信息与主机之间的分隔符
[91%5BIPv6 字面量定界符之一
]93%5DIPv6 字面量定界符之一
你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–948~122不编码与上面 9 个符号合计 71 个 ASCII 字符保持原样

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

常见问题

解出来的内容里还是 %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 面板,多点几次「开始解码」,可以看到没有新请求发出。

相关工具