JS:自定义GET查询参数序列化与解析方案(缩短URL)
嘿,我完全懂你想要缩短URL又能优雅传递JSON结构的需求!亚马逊那种紧凑的筛选参数格式确实很实用,下面给你几个更灵活的方案,解决你当前q[1]这类格式的局限性:
1. 扁平化键名方案(推荐,兼顾简洁与兼容性)
这是最接近亚马逊筛选器的格式,核心是把嵌套的JSON结构用.(或者_)拼接键名,数组则直接重复键名传递,不用依赖索引。
比如原JSON:
{ "filter": { "price": {"min": 10, "max": 100}, "category": ["electronics", "books"] } }
可以转成:filter.price.min=10&filter.price.max=100&filter.category=electronics&filter.category=books
如果想更短,还可以给常用键名加缩写,比如f.p.min=10&f.p.max=100&f.c=electronics&f.c=books。
优点:
- URL长度比
JSON.stringify短很多,可读性也不错 - 绝大多数后端框架(比如Express、Django)原生支持解析这种嵌套格式
- 数组处理更灵活,不用再写
q[1]这类索引式的参数,重复键名即可自动被解析为数组
实现示例(JS):
// 序列化:把JSON转成扁平化查询参数 function flattenJSON(obj, prefix = '') { const result = {}; for (const key in obj) { const newKey = prefix ? `${prefix}.${key}` : key; if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) { // 递归处理嵌套对象 Object.assign(result, flattenJSON(obj[key], newKey)); } else if (Array.isArray(obj[key])) { // 数组元素重复键名 obj[key].forEach(item => { result[newKey] = result[newKey] ? [...result[newKey], item] : [item]; }); } else { result[newKey] = obj[key]; } } return new URLSearchParams(result).toString(); } // 解析:把扁平化参数还原为JSON function unflattenParams(searchParams) { const obj = {}; for (const [key, value] of searchParams.entries()) { const keys = key.split('.'); let current = obj; for (let i = 0; i < keys.length; i++) { const k = keys[i]; if (i === keys.length - 1) { // 处理数组:重复键名转为数组 if (current[k]) { current[k] = Array.isArray(current[k]) ? [...current[k], value] : [current[k], value]; } else { current[k] = value; } } else { current[k] = current[k] || {}; current = current[k]; } } } return obj; }
2. 自定义缩写编码(极致缩短URL)
如果追求极致的URL长度,可以给常用的键名、枚举值提前约定缩写映射。比如把filter缩写成f,price.min缩写成pm,electronics缩写成e,上面的例子可以进一步压缩成:fpm=10&fpx=100&fc=e&fc=b
优点:URL长度最短
缺点:需要前后端严格约定映射规则,可读性差,维护成本较高,适合固定结构的场景
3. 轻量级二进制编码(适合复杂大结构)
如果你的JSON结构复杂、数据量较大,可以用MessagePack、BSON这类轻量级二进制编码,再转成URL安全的Base64(把+换成-,/换成_,去掉末尾的=)。
实现示例(JS):
import msgpack from 'msgpack-lite'; // 序列化 function encodeComplexJSON(obj) { const buffer = msgpack.encode(obj); // 转成URL安全的Base64 return btoa(String.fromCharCode(...new Uint8Array(buffer))) .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=+$/, ''); } // 解析 function decodeComplexJSON(str) { // 还原Base64格式 const restoredStr = str.replace(/-/g, '+').replace(/_/g, '/'); const buffer = new Uint8Array(atob(restoredStr).split('').map(c => c.charCodeAt(0))); return msgpack.decode(buffer); }
优点:能处理任意复杂JSON,编码后长度远小于JSON.stringify
缺点:URL是一串无意义字符,完全不可读,需要引入第三方编码库
方案选择建议
- 优先选扁平化键名方案:兼顾简洁、可读性和后端兼容性,解决你之前索引式数组的局限性
- 极致短URL需求:选自定义缩写编码,但要做好前后端规则同步
- 复杂大结构:选轻量级二进制编码,适合数据量大但不需要可读URL的场景
内容的提问来源于stack exchange,提问作者JCDenton
相关产品推荐
相关产品推荐

