Query 字符串解析

把 query 串或整条 URL 拆成键值对:先按 & 切段,再按每段第一个 = 切键值,最后各自解码。同一个 query 串用 decodeURIComponent 与用 URLSearchParams 解析,在加号处结果不同,本页把两种口径并排列出。重复键、空值与百分号编码错误都会被单独标记,全部在本地浏览器完成。

第三组 tag=a+b:decodeURIComponent 给 a+b,form-urlencoded 口径给 a b。加号是两种口径唯一的分歧点。
键值对5
去重后键数4
重复键1
query 串字符69
完整输入字符116

使用方法

  1. 输入框默认写着一条完整 URL,只写 ? 之后的 query 串也可以。页面会自动剥掉 ? 之前的部分与 # 之后的片段标识,按 Ctrl+Enter(Mac 上 Cmd+Enter)重新解析。
  2. 「表格里值的显示长度上限」默认 80,范围 8 到 500,步长 1。它只影响表格里的显示,超出会截断并加省略号,统计与导出仍按完整值计算。
  3. 解析结果按段顺序列出:键、原值、decodeURIComponent 值、form-urlencoded 值四列并排。两列值不一致时看原值里有没有加号,那通常就是分歧点。
  4. 重复出现的键会用醒目标记注出,并在统计里给出「去重后键数」与「重复键数」。同一个键出现两次不等于出错,很多接口就靠它传数组。
  5. 「反向生成的编码口径」决定下面反向框里空格写 %20 还是 +。两者都能被服务端读回,但按哪种口径解析就决定了值里的加号会不会变成空格。
  6. 反向框默认写着四行 key=value,按 Ctrl+Enter 生成 query 串。同一组键值对在两种口径下会生成两个不同的串:一个带 %20,一个带 +。
  7. 「复制结果」复制统计与整张键值表;「复制表格」复制键值表的制表符版本;「导出 CSV」把全部键值对存成带 BOM 的文件。
  8. 输入里没有等号、某段缺等号、百分号编码残缺、显示长度上限越界、反向框某行没有等号,都会给出写明段号或行号的提示。

这个 Query 字符串解析能解决什么问题

把 ? 后面那一串拆成键值对,看起来是个体力活,真正的坑在口径。同一个 q=a+b,用 decodeURIComponent 解出来是 a+b,用 URLSearchParams 取出来是 a b——因为 application/x-www-form-urlencoded 里加号表示空格,而 RFC 3986 的 query 里加号就是加号。本站这一页把两种口径并排列出,就是为了先把分歧摆到台面上。

第一类是调试接口。后端日志里记下的 query 串与前端代码里拼出来的串往往写法不同,把原始串粘进来,四列并排一对比,就能看出究竟是编码口径不一致,还是某处漏了解码。

第二类是排查重复键。?a=1&a=2 在 URLSearchParams 里 get 只取第一个、getAll 才取全部,在 PHP 里后一个覆盖前一个,在有些框架里则解析成数组。本页把重复键标记出来,避免你按「最后一个生效」的直觉去读。

第三类是核对分享链接。运营配的落地页链接常带 utm 参数与中文参数,中文会被编成百分号加十六进制的三字节一组。本页直接解回原文,能确认有没有被二次编码——二次编码的表现是解出来仍是一串百分号。

第四类是估算长度。URL 总长在实际环境里大约到 2000 字符就会出问题,IE 是 2083,现代浏览器与服务器各不相同。本页给出 query 串与完整输入的字符数,超限时会明确提示。

计算原理与变量说明

解析顺序是固定的三步:先按 & 切段 → 再按每段第一个 = 切键值 → 最后各自 decodeURIComponent。顺序不能颠倒。若先解码再切段,编码过的 %26(& 的编码)与 %3D(= 的编码)会被还原成分隔符,把本来属于值的内容切成新的键值对。

第二步只认第一个等号,这一点也很关键:a=1=2 的键是 a、值是 1=2,不是键 a=1 值 2。若整个串里一个等号都没有,本页直接报错而不是把整段当键——那多半是粘错了内容。

两种解码口径的差别只在加号。RFC 3986 的 query 里加号就是普通字符,decodeURIComponent("a+b") 得 a+b;而 form-urlencoded 口径把加号当空格,URLSearchParams 取 q=a+b 得 a b。%20 在任何口径下都是空格,所以 decodeURIComponent("a%20b") 得 a b,两种口径一致。

百分号编码本身按字节工作:一个字节变成百分号加两位十六进制,占 3 个字符。UTF-8 下一个汉字 3 字节,所以「中文」两个字的原始字节是 6,编码后是 %E4%B8%AD%E6%96%87 共 18 个字符,膨胀 9 倍。这是判断一段百分号串大概含几个汉字的快捷办法。

重复键的处理有两种语义,都要知道:?a=1&a=2 上,get("a") 取第一个得 1,getAll("a") 得 [1, 2];构造时 append() 是追加、set() 是删掉重复只留一个。数组语法另有几种写法:PHP 风格 a[]=1&a[]=2、带下标 a[0]=1&a[1]=2、Ruby 与 Node 的 qs 还支持 a[b]=1 这类嵌套。

最后一条是安全边界。query 里的敏感信息(令牌、密码)会同时写进浏览器历史、Referer 请求头与服务器访问日志,任何一环都可能外泄;能用 POST 传的就不要放在 query 里。

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

打开页面时的默认输入是一条完整 URL,query 部分是 q=%E6%9F%B3%E6%B3%89%E5%B7%A5%E5%85%B7&page=2&tag=a+b&tag=c%20d&flag=,共 69 个字符,完整输入 116 个字符。解析出 5 个键值对:q 的值是「柳泉工具」,page 的值是 2,tag 出现两次,flag 是空值。

tag 这一组最值得看:第一次出现是 tag=a+b,decodeURIComponent 给 a+b,form 口径给 a b;第二次出现是 tag=c%20d,两种口径都给 c d。所以同一批结果里,加号那组分歧、%20 那组一致。

反向框默认四行 q=柳泉工具、page=2、tag=a b、tag=c d。按百分号口径生成 q=%E6%9F%B3%E6%B3%89%E5%B7%A5%E5%85%B7&page=2&tag=a%20b&tag=c%20d;改成 form 口径则生成 q=%E6%9F%B3%E6%B3%89%E5%B7%A5%E5%85%B7&page=2&tag=a+b&tag=c+d。两个串长度相同,但只有第一个能被「加号就是加号」的解析口径正确读回。

Query 字符编码对照表

下表列出 query 里最容易出问题的十二个字符,按百分号编码逐行给出。写 query 时这些字符都应当编码,否则会被当成结构符号。

字符名称百分号编码不编码会怎样
空格%20被截断或被当成分隔符
+加号%2Bform 口径下被解成空格
&与号%26被当成下一组键值对的分界
=等号%3D被当成键值分隔,值被切走一段
?问号%3F被当成 query 起始位置
#井号%23之后的内容被当成片段标识丢弃
/斜杠%2F被当成路径分隔
:冒号%3A与 scheme 冒号混淆
%百分号%25被当成转义起始,后面两位被吃掉
,逗号%2C部分网关会做额外切分
中汉字%E4%B8%AD非 ASCII 必须编码,一个字 3 字节
@at 符%40与用户信息段的分隔符混淆

结果边界、舍入与适用说明

常见问题

为什么同一个加号有两种解析结果?

因为存在两套规则。RFC 3986 的 query 里加号就是加号,decodeURIComponent("a+b") 得 "a+b";application/x-www-form-urlencoded 里加号表示空格,URLSearchParams 取 q=a+b 得 "a b"。所以同一个 query 串,两种口径在加号处结果不同。

%20 和 + 到底该用哪个?

在 form-urlencoded 语境下两者都表示空格,但 %20 在任何口径下都是空格,而 + 只在 form 口径下是空格。要表达真正的加号,请写成 %2B,否则它在 form 口径下会被解成空格。

解析顺序为什么必须是先切后解?

若先解码再切段,编码过的 %26 与 %3D 会被还原成 & 与 =,把本来属于值的内容切成新的键值对。正确顺序是先按 & 切、再按第一个 = 切、最后各自 decodeURIComponent。

重复键该怎么读?

取决于对端实现。URLSearchParams 的 get 只取第一个,getAll 取全部;PHP 里后一个覆盖前一个;部分框架解析成数组。本页只负责标记重复,读到什么语义要看具体接口。

append 和 set 有什么区别?

append 是追加,同一个键会出现两次;set 会先删掉该键的所有旧值再写入,只留一个。想传数组就用 append,想覆盖就用 set,两者语义不同,混用会得到完全不同的 query 串。

中文参数为什么变成那么长一串?

因为百分号编码按字节工作。UTF-8 下一个汉字 3 字节,每字节变成 3 个字符,所以一个汉字占 9 个字符。中文两个字的原始字节是 6,编码后是 %E4%B8%AD%E6%96%87 共 18 个字符,膨胀 9 倍。

URL 多长会有问题?

实际环境里大约到 2000 字符就会出问题:IE 的硬限制是 2083,现代浏览器与服务器各不相同,超出会被截断或拒收。本页给出 query 串与完整输入的字符数,超 2000 时明确提示。

输入的内容会上传到服务器吗?

不会。query 串、键值对与所有选项只在本页脚本里参与运算,页面没有发起任何网络请求,刷新后输入即回到默认值。

相关工具