# @d-fischer/qs 中文文档

规范地址：https://npmcn.com/package/%40d-fischer/qs/

版本：7\.0\.2
npm 元数据更新时间：2022-04-05T02:28:23.580Z
中文译文更新时间：2026-11-11T07:39:45.513Z
软件包许可：BSD-3-Clause

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40d-fischer/qs
原文对照：https://npmcn.com/package/%40d-fischer/qs/?lang=original
项目主页：https://github.com/d-fischer/qs
源码仓库：https://github.com/d-fischer/qs

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：165 kB，28 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=0\.6
- 运行依赖：0 个
- 首次发布：2020-04-02T18:52:35.327Z
- 最新版本发布：2020-04-02T19:20:29.838Z
- 近 30 天下载量：22006（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：3（近 12 个月 0 个）

## 中文简介

一个支持嵌入和阵列的查询字符串解析器,其深度限制

## 安装

```sh
npm install @d-fischer/qs
```

也可以使用：`pnpm add @d-fischer/qs`、`yarn add @d-fischer/qs`、`bun add @d-fischer/qs`

## README

# 数量 [![Version Badge](http://versionbadg.es/ljharb/qs.svg)](https://npmjs.org/package/qs)

[![Build Status](https://api.travis-ci.org/ljharb/qs.svg)](https://travis-ci.org/ljharb/qs) [![dependency status](https://david-dm.org/ljharb/qs.svg)](https://david-dm.org/ljharb/qs) [![dev dependency status](https://david-dm.org/ljharb/qs/dev-status.svg)](https://david-dm.org/ljharb/qs?type=dev) [![License](http://img.shields.io/npm/l/qs.svg)](https://npmcn.com/package/%40d-fischer/qs/LICENSE) [![Downloads](http://img.shields.io/npm/dm/qs.svg)](http://npm-stat.com/charts.html?package=qs)

[![npm badge](https://nodei.co/npm/qs.png?downloads=true&stars=true)](https://npmjs.org/package/qs)

一个查询字符串解析和字符串化库,并附加一些安全性.

主维护者 : [约旦 哈班德](https://github.com/ljharb)

这个 **数量** 模块最初由 [TJ 霍洛韦楚克](https://github.com/visionmedia/node-querystring)。 。 。 .

## 使用量

```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');
```

### 分析对象

[](https://npmcn.com/package/%40d-fischer/qs/#readme-preventEval)

```javascript
qs.parse(string, [options]);
```

**数量** 允许您在查询字符串中创建嵌入对象, 绕出有方括号的子密钥的名称 `[]`。 。 。 . 例如,字符串 `'foo[bar]=baz'` 转换为:

```javascript
assert.deepEqual(qs.parse('foo[bar]=baz'), {
    foo: {
        bar: 'baz'
    }
});
```

使用时 `plainObjects` 选项,通过 `Object.create(null)` 因此,你应该知道,原型方法将不存在,用户可以将这些名称设定在他们喜欢的任何价值上:

```javascript
var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });
assert.deepEqual(nullObject, { a: { hasOwnProperty: 'b' } });
```

默认参数将覆盖对象原型上的属性会被忽略, 如果您希望保留这些字段的数据, 请使用 `plainObjects` 或设置 `allowPrototypes` 改为 `true` 这将允许用户输入来覆盖这些属性. _警告_ 启用这个选项通常是一个坏主意,因为它在试图使用被覆盖的属性时会造成问题. 总是小心这个选项.

```javascript
var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true });
assert.deepEqual(protoObject, { a: { hasOwnProperty: 'b' } });
```

URI 编码字符串也起作用 :

```javascript
assert.deepEqual(qs.parse('a%5Bb%5D=c'), {
    a: { b: 'c' }
});
```

也可以筑起你的物体,比如 `'foo[bar][baz]=foobarbaz'`数字 :

```javascript
assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), {
    foo: {
        bar: {
            baz: 'foobarbaz'
        }
    }
});
```

默认情况下, 当嵌入对象 **数量** 只有5个孩子会深陷其中 这意味着如果你试图解析一个字符串像 `'a[b][c][d][e][f][g][h][i]=j'` 您产生的对象将是:

```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);
```

这个深度可以通过通过 `depth` 选项到 `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' } } });
```

深度限制有助于减轻滥用情况 **数量** 用于解析用户输入,建议保持一个合理的小数字.

出于类似原因,默认 **数量** 仅解析可达1000个参数。 这可以通过通过一个 `parameterLimit` 选项 :

```javascript
var limited = qs.parse('a=b&c=d', { parameterLimit: 1 });
assert.deepEqual(limited, { a: 'b' });
```

要绕过主要的问题标记, 请使用 `ignoreQueryPrefix`数字 :

```javascript
var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });
assert.deepEqual(prefixed, { a: 'b', c: 'd' });
```

也可以通过一个可选的分隔符:

```javascript
var delimited = qs.parse('a=b;c=d', { delimiter: ';' });
assert.deepEqual(delimited, { a: 'b', c: 'd' });
```

限定符也可以是一个正则表达式:

```javascript
var regexed = qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ });
assert.deepEqual(regexed, { a: 'b', c: 'd', e: 'f' });
```

选项 `allowDots` 可用于启用点标记 :

```javascript
var withDots = qs.parse('a.b=c', { allowDots: true });
assert.deepEqual(withDots, { a: { b: 'c' } });
```

如果你必须处理 遗留浏览器或服务,有 也支持以等价- 8859-1 来解码 %- 编码的 octets :

```javascript
var oldCharset = qs.parse('a=%A7', { charset: 'iso-8859-1' });
assert.deepEqual(oldCharset, { a: '§' });
```

一些服务增加了初始 `utf8=✓` 值到窗体这样旧 Internet Explorer 版本更有可能提交表格为 utf- 8. 此外, 服务器可以检查值是否为错误 检查标记字符的编码和检测查询字符串 或者说 `application/x-www-form-urlencoded` 躯体是 _没有_ 以 utf-8,例如,如果表格有: `accept-charset` 参数或 包含页面的字符集不同.

**数量** 通过 `charsetSentinel` 选项. 如果指定,则 `utf8` 参数将从 返回对象。 将用来切换到 `iso-8859-1`编号 :`utf-8` 模式,取决于检查标记是如何编码的.

**重要**: 当您指定两个 `charset` 选项和 `charsetSentinel` 选项 `charset` 当它被覆盖的时候 请求中包含 `utf8` 实际参数 字符集可以推断. 在这个意义上 `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 &#10003; 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: 'ø' });
```

如果你想解码 `&#...;` 实际字符的语法, 您可以指定 `interpretNumericEntities` 选项以及:

```javascript
var detectedAsIso8859_1 = qs.parse('a=%26%239786%3B', {
    charset: 'iso-8859-1',
    interpretNumericEntities: true
});
assert.deepEqual(detectedAsIso8859_1, { a: '☺' });
```

当字符集在 `charsetSentinel` 模式.

### 分析阵列

**数量** 也可以使用相近的 `[]` 标记 :

```javascript
var withArray = qs.parse('a[]=b&a[]=c');
assert.deepEqual(withArray, { a: ['b', 'c'] });
```

您也可以指定一个索引:

```javascript
var withIndexes = qs.parse('a[1]=c&a[0]=b');
assert.deepEqual(withIndexes, { a: ['b', 'c'] });
```

注意一个数组中的索引和对象中的密钥的唯一区别是括号之间的值必须是数字 以创建数组。 当创建带有特定索引的数组时, **数量** 将会将一个稀疏的数组压缩到仅保存现有值 他们的顺序:

```javascript
var noSparse = qs.parse('a[1]=b&a[15]=c');
assert.deepEqual(noSparse, { a: ['b', 'c'] });
```

注意空字符串也是一个值,并将保留:

```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'] });
```

**数量** 还可以将数组中指定索引限制为最大索引 `20`。任何指数大于 `20` 将 改为以索引为键的对象。 当有人送来的时候 需要这样处理案件, `a[999999999]` 还要花很多时间 才能从这个巨大的阵列上爬出.

```javascript
var withMaxIndex = qs.parse('a[100]=b');
assert.deepEqual(withMaxIndex, { a: { '100': 'b' } });
```

这个限制可以通过通过 `arrayLimit` 选项 :

```javascript
var withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 });
assert.deepEqual(withArrayLimit, { a: { '1': 'b' } });
```

要完全禁用数组解析, 设置 `parseArrays` 改为 `false`。 。 。 .

```javascript
var noParsingArrays = qs.parse('a[]=b', { parseArrays: false });
assert.deepEqual(noParsingArrays, { a: { '0': 'b' } });
```

如果你混合标记, **数量** 将这两个项目合并为对象:

```javascript
var mixedNotation = qs.parse('a[0]=b&a[b]=c');
assert.deepEqual(mixedNotation, { a: { '0': 'b', b: 'c' } });
```

您也可以创建对象阵列 :

```javascript
var arraysOfObjects = qs.parse('a[][b]=c');
assert.deepEqual(arraysOfObjects, { a: [{ b: 'c' }] });
```

有些人用逗号加入数组, **数量** 能够解析 :

```javascript
var arraysOfObjects = qs.parse('a=b,c', { comma: true })
assert.deepEqual(arraysOfObjects, { a: ['b', 'c'] })
```

(单位:千美元)_此选项无法转换嵌入对象, 例如 `a={b:1},{c:d}`_(中文(简体) )

### 字符串

[](https://npmcn.com/package/%40d-fischer/qs/#readme-preventEval)

```javascript
qs.stringify(object, [options]);
```

当弦化时, **数量** 默认的 URI 编码输出。 对象按您期望的那样被字符串:

```javascript
assert.equal(qs.stringify({ a: 'b' }), 'a=b');
assert.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
```

此编码可以通过设置 `encode` 选项到 `false`数字 :

```javascript
var unencoded = qs.stringify({ a: { b: 'c' } }, { encode: false });
assert.equal(unencoded, 'a[b]=c');
```

通过设置密钥可禁用编码 `encodeValuesOnly` 选项到 `true`数字 :

```javascript
var encodedValues = qs.stringify(
    { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
    { encodeValuesOnly: true }
);
assert.equal(encodedValues,'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h');
```

这种编码也可以被设定为自定义编码方法所取代 `encoder` 选项 :

```javascript
var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str) {
    // Passed in values `a`, `b`, `c`
    return // Return encoded string
}})
```

_(注: `encoder` 如果 `encode` 实值 `false`(中文(简体) )_

模拟 `encoder` 有一个 `decoder` 选项 `parse` 以覆盖属性和值的解码:

```javascript
var decoded = qs.parse('x=z', { decoder: function (str) {
    // Passed in values `x`, `z`
    return // Return decoded string
}})
```

通过使用向编码器提供的类型参数,可以使用不同的逻辑编码密钥和值:

```javascript
var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) {
    if (type === 'key') {
        return // Encoded key
    } else if (type === 'value') {
        return // Encoded value
    }
}})
```

类型参数也提供给解码器:

```javascript
var decoded = qs.parse('x=z', { decoder: function (str, defaultEncoder, charset, type) {
    if (type === 'key') {
        return // Decoded key
    } else if (type === 'value') {
        return // Decoded value
    }
}})
```

超过这一点的例子将显示为输出没有为清晰度编码URI. 请注意,在这种情况下的返回价值 _将_ 在实际使用时被URI编码.

当数组被字符串化时,默认情况下它们会被赋予明确的指数:

```javascript
qs.stringify({ a: ['b', 'c', 'd'] });
// 'a[0]=b&a[1]=c&a[2]=d'
```

您可以通过设置 `indices` 选项到 `false`数字 :

```javascript
qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
// 'a=b&a=c&a=d'
```

你可以用这个 `arrayFormat` 选项以指定输出数组的格式:

```javascript
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'] }, { arrayFormat: 'comma' })
// 'a=b,c'
```

当对象被字符串时,默认情况下它们使用括号表示:

```javascript
qs.stringify({ a: { b: { c: 'd', e: 'f' } } });
// 'a[b][c]=d&a[b][e]=f'
```

您可以通过设置 : `allowDots` 选项到 `true`数字 :

```javascript
qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, { allowDots: true });
// 'a.b.c=d&a.b.e=f'
```

空字符串和空值会省略该值,但等值符号(=)仍然保留:

```javascript
assert.equal(qs.stringify({ a: '' }), 'a=');
```

无值的密钥( 如空对象或数组) 将不返回 :

```javascript
assert.equal(qs.stringify({ a: [] }), '');
assert.equal(qs.stringify({ a: {} }), '');
assert.equal(qs.stringify({ a: [{}] }), '');
assert.equal(qs.stringify({ a: { b: []} }), '');
assert.equal(qs.stringify({ a: { b: {}} }), '');
```

设置为属性 `undefined` 将完全省略:

```javascript
assert.equal(qs.stringify({ a: null, b: undefined }), 'a=');
```

查询字符串可选择预留一个问号:

```javascript
assert.equal(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }), '?a=b&c=d');
```

划界人也可以被用字符串取代:

```javascript
assert.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
```

如果您仅想要推翻序列化 `Date` 对象,您可以提供 `serializeDate` 选项 :

```javascript
var date = new Date(7);
assert.equal(qs.stringify({ a: date }), 'a=1970-01-01T00:00:00.007Z'.replace(/:/g, '%3A'));
assert.equal(
    qs.stringify({ a: date }, { serializeDate: function (d) { return d.getTime(); } }),
    'a=7'
);
```

你可以用这个 `sort` 选项以影响参数键的顺序:

```javascript
function alphabeticalSort(a, b) {
    return a.localeCompare(b);
}
assert.equal(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort }), 'a=c&b=f&z=y');
```

终于,你可以使用 `filter` 选项以限制字符串输出中将包含哪些密钥. 如果通过一个函数,将要求每个键获得替换值。 否则,如果你 通过一个数组, 用于选择字符串化的属性和数组索引 :

```javascript
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` 值作为空字符串处理 :

```javascript
var withNull = qs.stringify({ a: null, b: '' });
assert.equal(withNull, 'a=&b=');
```

解析不区分参数与无等号. 二者被转换为空字符串.

```javascript
var equalsInsensitive = qs.parse('a&b=');
assert.deepEqual(equalsInsensitive, { a: '', b: '' });
```

区分 `null` 值和空字符串使用 `strictNullHandling` 旗帜。 在结果中字符串 `null` 值没有 `=` 符号 :

```javascript
var strictNull = qs.stringify({ a: null, b: '' }, { strictNullHandling: true });
assert.equal(strictNull, 'a&b=');
```

解析数值不包含 `=` 返回到 `null` 使用该 `strictNullHandling` 旗帜 :

```javascript
var parsedStrictNull = qs.parse('a&b=', { strictNullHandling: true });
assert.deepEqual(parsedStrictNull, { a: null, b: '' });
```

完全跳过渲染密钥 `null` 值,使用 `skipNulls` 旗帜 :

```javascript
var nullsSkipped = qs.stringify({ a: 'b', c: null}, { skipNulls: true });
assert.equal(nullsSkipped, 'a=b');
```

如果你与遗留系统沟通 你可以切换到 `iso-8859-1` 使用 `charset` 选项 :

```javascript
var iso = qs.stringify({ æ: 'æ' }, { charset: 'iso-8859-1' });
assert.equal(iso, '%E6=%E6');
```

不存在于 `iso-8859-1` 将转换为数字 实体,类似于浏览器所做的:

```javascript
var numeric = qs.stringify({ a: '☺' }, { charset: 'iso-8859-1' });
assert.equal(numeric, 'a=%26%239786%3B');
```

你可以用这个 `charsetSentinel` 选项以 包括一个 `utf8=✓` 参数,如果检查标记是适当的编码, 与铁路上的Ruby和其他人在提交表格时的做法类似.

```javascript
var sentinel = qs.stringify({ a: '☺' }, { charsetSentinel: true });
assert.equal(sentinel, 'utf8=%E2%9C%93&a=%E2%98%BA');

var isoSentinel = qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' });
assert.equal(isoSentinel, 'utf8=%26%2310003%3B&a=%E6');
```

### 处理特殊字符集

默认情况下,字符的编码和解码是在 `utf-8`, (中文(简体) ), 财务报告和审定财务报表 `iso-8859-1` 支助也通过 `charset` 参数.

如果您想要将查询字符串编码到不同的字符集(即:. [移动 JIS](https://en.wikipedia.org/wiki/Shift_JIS)您可以使用 [`qs-iconv`](https://github.com/martinheidegger/qs-iconv) 库 :

```javascript
var encoder = require('qs-iconv/encoder')('shift_jis');
var shiftJISEncoded = qs.stringify({ a: 'こんにちは！' }, { encoder: encoder });
assert.equal(shiftJISEncoded, 'a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I');
```

也用于解码查询字符串 :

```javascript
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 });
assert.deepEqual(obj, { a: 'こんにちは！' });
```

### RFC 3986和RFC 1738空间编码

RFC3986 用作默认选项并编码 ' to _% 20 个_ 后向兼容. 同时,输出可以被按照RFC1738的"等于"来字符串.

```
assert.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC3986' }), 'a=b%20c');
assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');
```

## 警卫

请发电子邮件 [@ljharb:我无法想象](https://github.com/ljharb) 或见 [https://tidelift.com/security (中文(中国大陆) )](https://tidelift.com/security) 如果你有 潜在的安全弱点报告.

## qs 企业

作为Tidelift订阅的一部分提供

Qs和其他上千个软件包的维护者与Tidelift合作,为您用于构建应用程序的开源依赖提供商业支持和维护. 节省时间,降低风险,改善代码健康,同时向维护者支付使用的确切依赖性. [学多取.](https://tidelift.com/subscription/pkg/npm-qs?utm_source=npm-qs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)

## 常见问题

### @d-fischer/qs 是什么？

一个支持嵌入和阵列的查询字符串解析器,其深度限制

### 如何安装 @d-fischer/qs？

在项目目录运行 npm install @d-fischer/qs，或使用 pnpm add / yarn add / bun add。

### @d-fischer/qs 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @d-fischer/qs 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @d-fischer/qs 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=0\.6。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @d-fischer/qs 可以商用吗？

@d-fischer/qs 使用 BSD-3-Clause 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。另外不得用原作者名义为衍生产品背书。以上为概括，不构成法律意见，请以许可原文为准。

### @d-fischer/qs 的下载量有多少？

根据 npm 官方下载统计，@d-fischer/qs 在 2026/10/11 – 2026/11/09 这 30 天内被下载 22,006 次，日均约 734 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @d-fischer/qs 还在维护吗？

最新版本 7\.0\.2 发布于 2020/04/03（6 年前）；至今共发布 3 个版本，其中过去 12 个月发布了 0 个；首次发布于 2020/04/03。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

