URL解码
把%E2%9C%93还原为✓。双重编码的字符串、表单编码和残缺的输入都能处理,而不是直接拒绝。不存储任何内容。
- 绝不存储
- 无需排队,无需等待
- 无需注册,无水印
解码结果将显示在这里。
使用方法
粘贴编码后的文本
完整的URL、查询字符串,或者只是单个值。
按需选择解码方式
标准解码,或把+当作空格的表单解码。如果不确定,两种结果不同时页面会提示您。
复制结果
如果文本被编码了两次,就再解码一次——这种情况很常见,一旦看到就很容易识别。
没有任何工具能替您消除的歧义
解码在机制上很简单——找到每个后面跟着两位十六进制数字的%,把它还原成一个字节,再把这些字节按UTF-8读取——而其中恰好只有一处真正的歧义。加号可能表示空格,也可能就是加号。在提交的表单中它表示空格,这个约定比网络自身的URL规范还要古老。在路径片段中,它是字面字符。文本本身没有任何信息说明适用哪一种,所以页面会把两种解读都展示给您,而不是挑一种然后悄悄出错——这在最容易出问题的场景中最为重要:邮箱地址或Base64值里的加号是真实数据。
非ASCII文本中的每个字符都会变成好几段百分号序列,因为编码针对的是UTF-8字节,而不是字符:一个带重音的字母是两段,大多数符号是三段,一个emoji是四段。解码一段不是有效UTF-8的序列,就会得到替换字符——这通常说明文本是用另一种字符集编码的,或者在某个字符中间被截断了。
重复解码是安全漏洞,而不只是失误。如果一个值先被解码、再被校验、然后又被解码一次,攻击者就能让某些字符躲过校验:%252e%252e%252f能通过查找“../”的过滤器,因为解码一次后它仍是%2e%2e%2f,而第二次解码后,它就变成了过滤器本该拦截的路径穿越。只解码一次,然后校验,顺序绝不能反过来。
从未编码过的文本会原样返回,不会被弄乱——当您不确定一个字符串到底需不需要解码时,这正是有用的行为。后面没有跟着两位十六进制数字的百分号会保持不变,不会被当作错误——那是字面意义上的百分号,常见于直接粘贴而非经过编码的文本。
如果您需要的是别的
在代码中,解码器应该与编码器配套。JavaScript有decodeURIComponent;Python恰恰因为加号问题而区分了unquote和unquote_plus;PHP出于同样的原因提供rawurldecode和urldecode。更好的做法是交给URL类型或查询字符串解析器处理——大多数框架会替您解码参数,而之后再解码一次,正是上文所说的重复解码漏洞的由来。
如果是要查看一个很长的URL,而不是解码某个值,解析器比解码器更合适:python -c "import urllib.parse,sys; print(urllib.parse.urlparse(sys.argv[1]))"会把地址拆分成各个组成部分,让您在解码之前先看清哪一段是哪一段——链接出问题时,这通常才是真正要弄清的事。
常见问题
解码后文本里还有%25
说明它被编码了两次,这极其常见——每当一个已编码的值在经过重定向或日志层时又被编码一次,就会出现这种情况。%25是%字符本身的编码,所以第一次解码把%2520变成%20,第二次解码再把它变成空格。再解码一次即可。页面发现这种情况时会提示您。
“+”应该变成空格吗?
取决于字符串的来源,所以这是一个选项,而不是猜测。在application/x-www-form-urlencoded请求体中——也就是提交的HTML表单——+表示空格。在路径片段中,或者在只是经由URL传递的数据中,+是字面意义上的加号,把它变成空格会破坏这个值。最容易踩坑的是Base64字符串:它们包含真实的+字符,用表单方式解码就会把它毁掉。
字符串有损坏会怎样?
能解码的部分会被解码,其余部分保持原样,而不是全部拒绝。一个不属于有效转义序列的孤立%——在文本已被部分解码或被截断时很常见——会让浏览器自带的解码器抛出错误,什么都不返回。在这里,每个有效的转义序列都会被解码,孤立的字符原样保留,当您想读懂一行损坏的日志时,这要有用得多。
我的文本会被存储吗?
不会。不存储任何内容,也不发出任何请求。页面加载完成后,即使断开网络也照样能用。
能一次解码整个URL吗?
能。把整个URL粘贴进来——结构保持可读,只有编码的部分会被还原为文本,所以一个带有多个编码参数的长URL会变得真正可以读懂。
小贴士: 加号存在歧义:在查询字符串中它表示空格,在路径中则是字面意义上的加号。页面会按两种方式分别解码,并标明哪个是哪个,而不是去猜。从未经过百分号编码的文本会原样返回,不会被弄乱。
把这个工具放到您的网站上
博客、课程页面或帮助文章均可免费使用。粘贴一段代码,访客就能直接在您的页面上使用。