参数传递:从字符串拼接到 qs 标准化时代
无论是 Vue 还是 React 项目,几乎每个前端都在和“查询字符串(Query String)”打交道。
比如页面跳转参数、接口请求拼接、URL 状态同步…… 而 qs 就是处理这些的「工具」。
1. 什么是查询字符串(Query String)
在 URL 中,? 之后的部分就是查询字符串。如:
https://example.com/list?page=1&tags=vue,react
对应的数据结构可以理解为:
{page: 1,tags: ['vue', 'react']
}
但前后端之间,往往需要互相解析与拼接这些字符串。这就引出了三种常见方式:
工具 | 来源 | 常用场景 |
---|---|---|
qs | 第三方库 | Vue、React 项目中最常用 |
URLSearchParams | 原生 API | 简单参数解析/构建 |
querystring | Node.js 内置模块 | 后端常用(Node 环境) |
2. qs 是什么?
qs(全称 querystring)是一个功能强大的第三方库,用于:
把对象转成 URL 查询字符串(序列化);
把 URL 查询字符串转成对象(解析)。
2.1 安装
npm install qs
# 或
yarn add qs
2.2 基础使用示例
1、对象 → 查询字符串
import qs from 'qs';const params = {name: '张三',age: 25,tags: ['vue', 'ts', 'vite']
};console.log(qs.stringify(params));
输出:
name=张三&age=25&tags[0]=vue&tags[1]=ts&tags[2]=vite// 控制台:name=%E5%BC%A0%E4%B8%89&age=25&tags%5B0%5D=vue&tags%5B1%5D=ts&tags%5B2%5D=vite
想让数组更简洁?
qs.stringify(params, { arrayFormat: 'repeat' });
// => name=张三&age=25&tags=vue&tags=ts&tags=vite
常见 arrayFormat 选项对比:
arrayFormat | 示例输出 | 说明 |
---|---|---|
indices | tags[0]=vue&tags[1]=ts | 默认形式 |
brackets | tags[]=vue&tags[]=ts | PHP风格 |
repeat | tags=vue&tags=ts | REST风格 |
comma | tags=vue,ts | 用逗号拼接 |
2、查询字符串 → 对象
qs.parse('name=张三&age=25&tags[0]=vue&tags[1]=ts');
输出:
{name: '张三',age: '25',tags: ['vue', 'ts']
}
3. 与其他方法对比
3.1 URLSearchParams(原生方法)
const params = new URLSearchParams({ name: '张三', tags: ['vue', 'ts'] });
console.log(params.toString()); // name=张三&tags=vue,ts
解析:
Object.fromEntries(new URLSearchParams('a=1&b=2')); // { a: '1', b: '2' }
优点:原生支持,无需依赖;浏览器原生 API,性能高。
缺点:
1、不支持嵌套对象,举个 🌰
const params = new URLSearchParams({user: { name: 'Tom', age: 20 },city: 'Shanghai'
});console.log(params.toString());
user=[object Object]&city=Shanghai
问题说明:
- URLSearchParams 只支持平面对象(key-value 结构)。
- 对于嵌套对象,直接被强制转换为字符串 [object Object],无法序列化为层级结构。
- 后端无法解析出 { name: 'Tom', age: 20 } 这个对象。
2、数组解析不统一
const params = new URLSearchParams({ids: [1, 2, 3]
});console.log(params.toString());
ids=1,2,3
问题说明:
- 浏览器会将数组强转为字符串 "1,2,3",实际上后端收到的是 ids: "1,2,3",而不是数组。
- 不同浏览器、不同服务端框架(如 Java、Node、Python)解析方式不一致。
3、Node 低版本不兼容。
ReferenceError: URLSearchParams is not defined
问题说明:在 Node.js v10 以下版本 不原生支持。
3.2 querystring(Node 内置模块)
import querystring from 'querystring';const obj = {name: 'Tom',age: 20,tags: ['vue', 'react']
};// 对象 → 查询字符串
const str = querystring.stringify(obj);
console.log('stringify:', str);// 查询字符串 → 对象
const parsed = querystring.parse(str);
console.log('parse:', parsed);
预期输出:
stringify: name=Tom&age=20&tags=vue&tags=react
parse: [Object: null prototype] {name: 'Tom',age: '20',tags: [ 'vue', 'react' ]
}
优点:轻量;Node 后端原生可用。
缺点:
1、嵌套对象不支持
const nested = { user: { name: 'Tom' }, city: 'Shanghai' };console.log(querystring.stringify(nested));
输出:
user=[object Object]&city=Shanghai
2、Node 环境限定
querystring 是 Node.js 内置模块,浏览器环境不能直接用。
3、维护已停滞
3.3 qs(第三方库)
优点:支持深层嵌套对象;灵活的数组序列化;支持前后端统一使用;可配置项多。
缺点:多一个依赖;大对象序列化略慢(对性能敏感项目需注意)。
4. qs 实战场景
4.1 axios
POST 表单请求
import axios from 'axios';
import qs from 'qs';axios.post('/api/login', qs.stringify({username: 'admin',password: '123456'
}));
GET 参数序列化
axios.get('/api/list', {params: { page: 1, tags: ['vue', 'react'] },paramsSerializer: params => qs.stringify(params, { arrayFormat: 'repeat' })
});
效果:
GET /api/list?page=1&tags=vue&tags=react
4.2 Vue/React
1、路由拼接
router.push(`/detail?${qs.stringify({ id: 123, tab: 'info' })}`)
2、解析 URL 参数
const query = qs.parse(location.search, { ignoreQueryPrefix: true });
console.log(query);
3、统一参数序列化
axios.defaults.paramsSerializer = params => qs.stringify(params, { arrayFormat: 'brackets' });
5. 注意事项
1、若解析不可信字符串,建议关闭原型链继承:
qs.parse(str, { allowPrototypes: false });
2、大型嵌套对象会带来性能消耗。
3、尽量避免直接将用户输入的字符串传入 parse()。
选择建议
场景 | 推荐工具 | 说明 |
---|---|---|
简单参数(少量、扁平) | URLSearchParams | 无需依赖,原生快 |
嵌套对象、数组结构 | qs | 处理灵活,兼容性强 |
Node.js 后端 | querystring / qs | Node 内置或通用方案 |
大型前端项目(axios 等) | qs | 事实标准 |