# URL查询字符串 querystring
30 秒速记
querystring是Node.js老模块,官方标了legacy;新代码用全局的URLSearchParams- 重复键:
querystring.parse给数组,URLSearchParams用get拿第一个、getAll拿全部 - 值永远是字符串,
page=2拿到的是'2',数字布尔要自己转 - 空格编码不同:
querystring是%20,URLSearchParams是+ querystring.parse默认最多解析1000个键(maxKeys),防恶意超长参数
查询字符串就是 ? 后面那串 a=1&b=2,Node.js 里老办法是 querystring 模块,新办法是 URLSearchParams。 两者都能解析和拼接,但细节不同:重复键 querystring 直接给数组,URLSearchParams 要用 getAll;空格一个编成 %20、一个编成 +。不管用哪个,拿到的值都是字符串,page=2 拿到 '2',直接相加就变成字符串拼接。所以我在接口入口一定会配一层 schema 校验,把类型、默认值、是否允许多值都定下来。
理解「URL查询字符串 querystring」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。
工程中还要验证退出码、资源清理和异常输入。属于 buffer 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。
面试官追问
追问 1?tag=js&tag=node,querystring.parse 和 URLSearchParams 各拿到什么?
querystring.parse 得到 { tag: ['js', 'node'] };URLSearchParams 的 get('tag') 是 'js',getAll('tag') 是两个都有。要是用 Object.fromEntries(params) 转对象,只剩最后一个 'node'。
追问 2筛选接口有时收到字符串、有时收到数组,代码一会儿正常一会儿报错,怎么治?
这是重复键导致的类型不稳定。入口统一规整:[].concat(q.tag ?? []) 永远转数组,或者用 getAll。更好的是用 zod 这类 schema 明确每个字段是单值还是多值。
追问 3?debug=false,代码里 if (q.debug) 却进了分支,为什么?
'false' 是非空字符串,是真值。查询参数要显式转换,比如 q.debug === 'true',别依赖 JS 的真假值判断。
追问 4有人传了几万个参数的超长查询串,服务会不会被拖垮?
querystring.parse 默认 maxKeys 是 1000,超出部分直接丢掉,能挡一部分。但更该在网关或框架层限制 URL 总长度,Node.js 本身对请求头总大小默认也有约 16KB 的上限。
# 模块概述
30 秒速记
querystring四个方法:parse、stringify、escape、unescape,日常只用前两个parse:字符串 → 对象;stringify:对象 → 字符串parse返回的对象没有原型,obj.hasOwnProperty会报错- 不做嵌套:
a[b]=1解析出的键就是'a[b]',要嵌套用qs库 decode/encode是parse/stringify的别名
querystring 是 Node.js 处理查询参数的老模块,核心就两个方法:parse 把字符串解析成对象,stringify 反过来。 用起来很简单,但有两个细节常被问。一是 parse 返回的对象是用 Object.create(null) 造的,没有原型,obj.hasOwnProperty('a') 直接报错,要用 Object.hasOwn(obj, 'a')。二是它不支持嵌套,user[name]=tom 解析出来键名就是 'user[name]',Express 能解析嵌套是因为默认用了 qs 库。
在nodejs中,提供了querystring这个模块,用来做url查询参数的解析,使用非常简单。
模块总共有四个方法,绝大部分时,我们只会用到 .parse()、 **.stringify()**两个方法。剩余的方法,感兴趣的同学可自行查看文档。
- .parse():对url查询参数(字符串)进行解析,生成易于分析的json格式。
- .stringif():跟**.parse()**相反,用于拼接查询查询。
querystring.parse(str[, sep[, eq[, options]]])
querystring.stringify(obj[, sep[, eq[, options]]])
面试官追问
追问 1querystring.parse(str).hasOwnProperty('a') 报 is not a function,为什么?
返回的对象没有原型,自然没有 hasOwnProperty。改成 Object.hasOwn(obj, 'a') 或 'a' in obj。这样设计是为了防止 ?__proto__=x 这类参数污染原型。
追问 2前端传 user[name]=tom&user[age]=18,querystring 能解析成嵌套对象吗?
不能,得到的是 { 'user[name]': 'tom', 'user[age]': '18' }。要嵌套就用 qs,不过嵌套查询串本身就容易引发原型污染和类型混乱,复杂结构我更倾向放到 POST 的 JSON 里。
追问 3querystring.parse('a=1+2') 拿到的 a 是什么?
'1 2',+ 会被当成空格解码。如果值里真要一个加号,传的时候得编码成 %2B。
追问 4querystring 和 URLSearchParams,新项目选哪个?
选 URLSearchParams,浏览器和 Node.js 都是全局可用,前后端一套写法。querystring 唯一的优势是能自定义分隔符,对接非标准格式时才用得上。
# 查询参数解析:querystring.parse()
30 秒速记
querystring.parse(str, sep = '&', eq = '=', options)'nick=casper&age=24'→{ nick: 'casper', age: '24' },age是字符串sep/eq换分隔符:parse('name-chyingp|country-cn', '|', '-')也能解析options.maxKeys默认1000,传0不限;options.decodeURIComponent可换解码函数- 边界:
a→{ a: '' },a=→{ a: '' },重复键 → 数组
querystring.parse 把 a=1&b=2 这种字符串拆成对象,默认用 & 分参数、= 分键值。 第二三个参数可以换掉这两个符号,适合对接 name-chyingp|country-cn 这种自定义格式,不用自己写两层 split。第四个参数用得少,主要是 maxKeys,默认只解析前 1000 个键。要记住的是它不做类型推断,age=24 拿到的是字符串 '24',空值和没写等号都是空字符串,重复键会变成数组。
参数:querystring.parse(str[, sep[, eq[, options]]])
第四个参数几乎不会用到,直接不讨论. 第二个, 第三个其实也很少用到,但某些时候还是可以用一下。直接看例子
var querystring = require('querystring');
var str = 'nick=casper&age=24';
var obj = querystring.parse(str);
console.log(JSON.stringify(obj, null, 4));
输出如下
{
"nick": "casper",
"age": "24"
}
再来看下sep、eq有什么作用。相当于可以替换&、=为自定义字符,对于下面的场景来说还是挺省事的。
var str1 = 'nick=casper&age=24&extra=name-chyingp|country-cn';
var obj1 = querystring.parse(str1);
var obj2 = querystring.parse(obj1.extra, '|', '-');
console.log(JSON.stringify(obj2, null, 4));
输出如下
{
"name": "chyingp",
"country": "cn"
}
面试官追问
追问 1age=24 解析出来直接 obj.age + 1,结果是 '241',怎么改?
parse 只拆字符串不转类型,要显式 Number(obj.age),并且判断 Number.isNaN
