qs.js学习教程
简介
Nodejs中内置了一个querystring
模块,可以用来解析与格式化 URL 查询字符串,但是它的功能比较简单,无法解析嵌套的对象或者数组等,还有无法解析null
或者一些特殊字符,因此,qs.js
就是为了解决这些问题而诞生的。
解析对象
var qs = require('qs');
qs.parse(string, [options]);
qs
允许你使用[]
来创建一个嵌套的对象:
qs.parse('foo[bar]=baz')
将会解析为:
{
foo: {
bar: 'baz'
}
}
如果使用querystring
模块进行解析的话,则会出现如下的效果:
{ 'foo[bar]': 'baz' }
如果你加入了{ plainObjects: true }
选项,则会通过Object.create(null)
来创建一个对象,该对象上不会有任何原型,如果使用{ allowPrototypes: true }
选项,则该对象上有原型:
var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });
var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true });
nullObject.toString //undefined
protoObject.toString // [Function: toString]
URI编码格式将会被解析成:
qs.parse('a%5Bb%5D=c')// a: { b: 'c' }
qs
也支持嵌套解析,但是默认只解析到第5层:
var string = 'a[b][c][d][e][f][g][h][i]=j';
qs.parse(string)
//输出如下
{
a: {
b: {
c: {
d: {
e: {
f: {
'[g][h][i]': 'j'
}
}
}
}
}
}
}
你可以自行设置解析的嵌套深度{ depth: 5 }
,默认地,qs
会解析最多1000个参数,你可以通过设置parameterLimit
来自行设置:
var limited = qs.parse('a=b&c=d', { parameterLimit: 1 }); //{ a: 'b' }
如果想要忽略?
,可以设置ignoreQueryPrefix
:
var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });//{ a: 'b', c: 'd' }
你也可以通过设置delimiter
来自定义分隔符:
var delimited = qs.parse('a=b;c=d', { delimiter: ';' }); //{ a: 'b', c: 'd' }
var regexed = qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ }); //{ a: 'b', c: 'd', e: 'f' }
你可以设置allowDots
来解析使用.
的标记语法:
var withDots = qs.parse('a.b=c', { allowDots: true }); //{ a: { b: 'c' } }
解析数组
你可以使用[]
告诉qs
这是一个数组:
var withArray = qs.parse('a[]=b&a[]=c'); //{ a: ['b', 'c'] }
var withIndexes = qs.parse('a[1]=c&a[0]=b'); //{ a: ['b', 'c'] }
var withEmptyString = qs.parse('a[]=&a[]=b'); //{ a: ['', 'b'] }
var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c'); //{ a: ['b', '', 'c'] }
注意[index]
虽然可以表示数组的索引,但是最多不能超过20
,如果超过了就会把它当做一个属性来解析,你也可以通过设置arrayLimit
来指定最大索引上限,parseArrays
是否解析成数组:
var withMaxIndex = qs.parse('a[100]=b'); //{ a: { '100': 'b' } }
var withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 }); //{ a: { '1': 'b' } }
var noParsingArrays = qs.parse('a[]=b', { parseArrays: false });//{ a: { '0': 'b' } }
字符化
默认的qs
会使用URI编码格式输出,你也可以使用{ encode: false }
来关闭:
qs.stringify({ a: { b: 'c' } })//'a%5Bb%5D=c'
qs.stringify({ a: { b: 'c' } }, { encode: false }); //'a[b]=c'
你可以设置{ encodeValuesOnly: true }
选项来控制只对值进行编码:
qs.stringify(
{ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
{ encodeValuesOnly: true }
);//'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h'
你还可以通过设置encoder
选项来自定义编码方法:
var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str) {
// a[b], c
return str+'-'
}})// a[b]-=c-
注意,如果encode
为false
时,encoder
则不起作用。
对应地,你也可以设置decoder
选项来自定义解码方法。
var decoded = qs.parse('x=z', { decoder: function (str) {
// `x`, `z`
return // Return decoded string
}})
更多用法请参考以下例子:
qs.stringify({ a: ['b', 'c', 'd'] }); // 'a[0]=b&a[1]=c&a[2]=d'
qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }); // 'a=b&a=c&a=d'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }) // 'a[0]=b&a[1]=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }) // 'a[]=b&a[]=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }) // 'a=b&a=c'
qs.stringify({ a: { b: { c: 'd', e: 'f' } } });// 'a[b][c]=d&a[b][e]=f'
qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, { allowDots: true });// 'a.b.c=d&a.b.e=f'
qs.stringify({ a: '' })// 'a='
qs.stringify({ a: [] }) //''
qs.stringify({ a: {} })//''
qs.stringify({ a: [{}] })//''
qs.stringify({ a: { b: []} })//''
qs.stringify({ a: { b: {}} })//''
qs.stringify({ a: null, b: undefined })//'a='
qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true })//'?a=b&c=d'
qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' })//'a=b;c=d'
qs.stringify({ a: date }, { serializeDate: function (d) { return d.getTime(); } })//'a=7'
你还可以自定义sort
属性方法来对属性进行排序:
function alphabeticalSort(a, b) {
return a.localeCompare(b);
}
qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort })//'a=c&b=f&z=y'
你还可以通过设置filter
属性方法来设置过滤器对属性进行过滤:
function filterFunc(prefix, value) {
if (prefix == 'b') {
// Return an `undefined` value to omit a property.
return;
}
if (prefix == 'e[f]') {
return value.getTime();
}
if (prefix == 'e[g][0]') {
return value * 2;
}
return value;
}
qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc });// 'a=b&c=d&e[f]=123&e[g][0]=4'
qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] });// 'a=b&e=f'
qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] });// 'a[0]=b&a[2]=d'
Null
值处理
默认地,Null
值会被解析为空字符串:
var withNull = qs.stringify({ a: null, b: '' }); //'a=&b='
解析器不区分参数是否含有等号或者不含都会转换为空:
qs.parse('a&b='); //{ a: '', b: '' }
在字符串化的时候,可以使用strictNullHandling
选项来区分Null
值和空,输出结果中Null
值将不会含有等号:
qs.stringify({ a: null, b: '' }, { strictNullHandling: true })//'a&b='
如果要将没有等号的字符串值解析为Null
的话,也可以使用strictNullHandling
选项:
qs.parse('a&b=', { strictNullHandling: true }) //{ a: null, b: '' }
skipNulls
选项可以忽略Null
值的解析:
qs.stringify({ a: 'b', c: null}, { skipNulls: true }) //'a=b'
处理特殊字符集
qs.js
默认使用的是utf-8
进行编码和解码,如果你想要处理特殊字符集的话,你可以使用qs-iconv:
var encoder = require('qs-iconv/encoder')('shift_jis');
var shiftJISEncoded = qs.stringify({ a: 'こんにちは!' }, { encoder: encoder });//'a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I'
var decoder = require('qs-iconv/decoder')('shift_jis');
var obj = qs.parse('a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I', { decoder: decoder })//{ a: 'こんにちは!' }
RFC 3986 和RFC 1738 空格编码
RFC3986默认会将空格解析为%20
,RFC1738会把空格解析为+
:
qs.stringify({ a: 'b c' })//'a=b%20c'
qs.stringify({ a: 'b c' }, { format : 'RFC3986' })// 'a=b%20c'
qs.stringify({ a: 'b c' }, { format : 'RFC1738' })//'a=b+c'