Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
Q

qs

> 编程语言
Open source

A querystring parser and serializer with nesting support

8.9K stars0 likes1 views
WebsiteGitHub

About

A querystring parser and serializer with nesting support

# qs [![Version Badge][npm-version-svg]][package-url] [![github actions][actions-image]][actions-url] [![coverage][codecov-image]][codecov-url] [![License][license-image]][license-url] [![Downloads][downloads-image]][downloads-url] [![npm badge][npm-badge-png]][package-url] A querystring parsing and stringifying library with some added security. Lead Maintainer: [Jordan Harband](https://github.com/ljharb) The **qs** module was originally created and maintained by [TJ Holowaychuk](https://github.com/visionmedia/node-querystring). ## Usage ```javascript var qs = require('qs'); var assert = require('assert'); var obj = qs.parse('a=c'); assert.deepEqual(obj, { a: 'c' }); var str = qs.stringify(obj); assert.equal(str, 'a=c'); ``` ### Parsing Objects [](#preventEval) ```javascript qs.parse(string, [options]); ``` **qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]`. For example, the string `'foo[bar]=baz'` converts to: ```javascript assert.deepEqual(qs.parse('foo[bar]=baz'), { foo: { bar: 'baz' } }); ``` When using the `plainObjects` option the parsed value is returned as a null object, created via `{ __proto__: null }` and as such you should be aware that prototype methods will not exist on it and a user may set those names to whatever value they like: ```javascript var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true }); assert.deepEqual(nullObject, { a: { hasOwnProperty: 'b' } }); ``` By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use `plainObjects` as mentioned above, or set `allowPrototypes` to `true` which will allow user input to overwrite those properties. *WARNING* It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option. ```javascript var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }); assert.deepEqual(protoObject, { a: { hasOwnProperty: 'b' } }); ``` URI encoded strings work too: ```javascript assert.deepEqual(qs.parse('a%5Bb%5D=c'), { a: { b: 'c' } }); ``` You can also nest your objects, like `'foo[bar][baz]=foobarbaz'`: ```javascript assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), { foo: { bar: { baz: 'foobarbaz' } } }); ``` Since v6.14.1 and v6.15.2, `parse` interprets nested bracket groups more consistently. Query strings with unbalanced `[`/`]` can produce different results than in 6.15.1; see [#558](https://github.com/ljharb/qs/issues/558). By default, when nesting objects **qs** will only parse up to 5 children deep. This means if you attempt to parse a string like `'a[b][c][d][e][f][g][h][i]=j'` your resulting object will be: ```javascript var expected = { a: { b: { c: { d: { e: { f: { '[g][h][i]': 'j' } } } } } } }; var string = 'a[b][c][d][e][f][g][h][i]=j'; assert.deepEqual(qs.parse(string), expected); ``` This depth can be overridden by passing a `depth` option to `qs.parse(string, [options])`: ```javascript var deep = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 }); assert.deepEqual(deep, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } }); ``` You can configure **qs** to throw an error when parsing nested input beyond this depth using the `strictDepth` option (defaulted to false): ```javascript try { qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1, strictDepth: true }); } catch (err) { assert(err instanceof RangeError); assert.strictEqual(err.message, 'Input depth exceeded depth option of 1 and strictDepth is true'); } ``` The depth limit helps mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number. The strictDepth option adds a layer of protection by throwing an error when the limit is exceeded, allowing you to catch and handle such cases. For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option: ```javascript var limited = qs.parse('a=b&c=d', { parameterLimit: 1 }); assert.deepEqual(limited, { a: 'b' }); ``` If you want an error to be thrown whenever a limit is exceeded (eg, `parameterLimit`, `arrayLimit`), set the `throwOnLimitExceeded` option to `true`. This option will generate a descriptive error if the query string exceeds a configured limit. ```javascript try { qs.parse('a=1&b=2&c=3&d=4', { parameterLimit: 3, throwOnLimitExceeded: true }); } catch (err) { assert(err instanceof Error); assert.strictEqual(err.message, 'Parameter limit exceeded. Only 3 parameters allowed.'); } ``` When `throwOnLimitExceeded` is set to `false` (default), **qs** will parse up to the specified `parameterLimit` and ignore the rest without throwing an error. Note that `parameterLimit` only bounds the number of `&`-delimited parameters; it does not limit how many values a single parameter expands into. In particular, when `comma: true` is enabled, a single parameter's value is split on commas into arbitrarily many elements, which `parameterLimit` does not constrain. Setting `throwOnLimitExceeded: true` (see `arrayLimit` below) makes **qs** reject a query string with more than `parameterLimit` parameters, one that uses an array index of `arrayLimit` or greater, or one that would produce any array longer than `arrayLimit`, including an array produced by comma splitting. `arrayLimit` applies to each array separately, including each parameter's comma-split value, so the total number of values across all parameters can still reach `parameterLimit` times `arrayLimit`, which is 20,000 at the default limits; always bound the input size at the transport layer as well (e.g. an HTTP body-size limit). To bypass the leading question mark, use `ignoreQueryPrefix`: ```javascript var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true }); assert.deepEqual(prefixed, { a: 'b', c: 'd' }); ``` An optional delimiter can also be passed: ```javascript var delimited = qs.parse('a=b;c=d', { delimiter: ';' }); assert.deepEqual(delimited, { a: 'b', c: 'd' }); ``` Delimiters can be a regular expression too: ```javascript var regexed = qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ }); assert.deepEqual(regexed, { a: 'b', c: 'd', e: 'f' }); ``` Option `allowDots` can be used to enable dot notation: ```javascript var withDots = qs.parse('a.b=c', { allowDots: true }); assert.deepEqual(withDots, { a: { b: 'c' } }); ``` Option `decodeDotInKeys` can be used to decode dots in keys Note: it implies `allowDots`, so `parse` will error if you set `decodeDotInKeys` to `true`, and `allowDots` to `false`. ```javascript var withDots = qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { decodeDotInKeys: true }); assert.deepEqual(withDots, { 'name.obj': { first: 'John', last: 'Doe' }}); ``` Option `allowEmptyArrays` can be used to allow empty array values in an object ```javascript var withEmptyArrays = qs.parse('foo[]&bar=baz', { allowEmptyArrays: true }); assert.deepEqual(withEmptyArrays, { foo: [], bar: 'baz' }); ``` Option `duplicates` can be used to change the behavior when duplicate keys are encountered ```javascript assert.deepEqual(qs.parse('foo=bar&foo=baz'), { foo: ['bar', 'baz'] }); assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'combine' }), { foo: ['bar', 'baz'] }); assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'first' }), { foo: 'bar' }); assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'last' }), { foo: 'baz' }); ``` Note that keys with bracket notation (`[]`) always combine into arrays, regardless of the `duplicates` setting: ```javascript assert.deepEqual(qs.parse('a=1&a=2&b[]=1&b[]=2', { duplicates: 'last' }), { a: '2', b: ['1', '2'] }); ``` If you have to deal with legacy browsers or services, there's also support for decoding percent-encoded octets as iso-8859-1: ```javascript var oldCharset = qs.parse('a=%A7', { charset: 'iso-8859-1' }); assert.deepEqual(oldCharset, { a: '§' }); ``` Some services add an initial `utf8=✓` value to forms so that old Internet Explorer versions are more likely to submit the form as utf-8. Additionally, the server can check the value against wrong encodings of the checkmark character and detect that a query string or `application/x-www-form-urlencoded` body was *not* sent as utf-8, eg. if the form had an `accept-charset` parameter or the containing page had a different character set. **qs** supports this mechanism via the `charsetSentinel` option. If specified, the `utf8` parameter will be omitted from the returned object. It will be used to switch to `iso-8859-1`/`utf-8` mode depending on how the checkmark is encoded. **Important**: When you specify both the `charset` option and the `charsetSentinel` option, the `charset` will be overridden when the request contains a `utf8` parameter from which the actual charset can be deduced. In that sense the `charset` will behave as the default charset rather than the authoritative charset. ```javascript var detectedAsUtf8 = qs.parse('utf8=%E2%9C%93&a=%C3%B8', { charset: 'iso-8859-1', charsetSentinel: true }); assert.deepEqual(detectedAsUtf8, { a: 'ø' }); // Browsers encode the checkmark as ✓ when submitting as iso-8859-1: var detectedAsIso8859_1 = qs.parse('utf8=%26%2310003%3B&a=%F8', { charset: 'utf-8', charsetSentinel: true }); assert.deepEqual(detectedAsIso8859_1, { a: 'ø' }); ``` If you want to decode the `&#...;` syntax to the actual character, you can specify the `interpretNumericEntities` option as well: ```javascript var detectedAsIso8859_1 = qs.parse('a=%26%239786%3B', { charset: 'iso-8859-1', interpretNumericEntities: true }); assert.deepEqual(detectedAsIso8859_1, { a: '☺' }); ``` It also works when the charset has been detected in `charsetSentinel` mode. ### Parsing Arrays **qs** can also parse arrays using a similar `[]` notation: ```javascript var withArray = qs.parse('a[]=b&a[]=c'); assert.deepEqual(withArray, { a: ['b', 'c'] }); ``` You may specify an index as well: ```javascript var withIndexes = qs.parse('a[1]=c&a[0]=b'); assert.deepEqual(withIndexes, { a: ['b', 'c'] }); ``` Note that the only difference between an index in an array and a key in an object is that the value between the brackets must be a number to create an array. When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving their order: ```javascript var noSparse = qs.parse('a[1]=b&a[15]=c'); assert.deepEqual(noSparse, { a: ['b', 'c'] }); ``` You may also use `allowSparse` option to parse sparse arrays: ```javascript var sparseArray = qs.parse('a[1]=2&a[3]=5', { allowSparse: true }); assert.deepEqual(sparseArray, { a: [, '2', , '5'] }); ``` Note that an empty string is also a value, and will be preserved: ```javascript var withEmptyString = qs.parse('a[]=&a[]=b'); assert.deepEqual(withEmptyString, { a: ['', 'b'] }); var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c'); assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] }); ``` **qs** will also limit arrays to a maximum of `20` elements. Any array members with an index of `20` or greater will instead be converted to an object with the index as the key. This is needed to handle cases when someone sent, for example, `a[999999999]` and it will take significant time to iterate over this huge array. Since v6.14.1 and v6.15.2, the arrayLimit now applies to arrays specified using both the `[]` and `[0]` syntaxes. ```javascript var withMaxIndex = qs.parse('a[100]=b'); assert.deepEqual(withMa

GitHub Issues· 0 open

View all on GitHub

No open issues yet, or sync has not completed.

Highlights

  • •JavaScript
  • •browsers
  • •encoding
  • •javascript
  • •node

> Tags

JavaScriptbrowsersencodingjavascriptnode

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言