Project Icon

neoqs

现代化的轻量级查询字符串解析库

neoqs是qs的TypeScript重写版本,提供现代化、轻量级且完全兼容的查询字符串解析和生成功能。该库支持零依赖、ESM优先设计,保持与qs相同的API。neoqs能够解析嵌套对象和数组,同时提供深度限制和参数数量限制等安全选项。此外,neoqs还提供legacy build以兼容旧版浏览器和Node环境。

neoqs

一个具有额外安全功能的查询字符串解析和字符串化库。它是 qs 的一个分支和 TypeScript 重写版本,旨在成为现代、轻量级但完全向后兼容 qs 的库。

主要维护者:Puru Vijay

qs 模块最初由 TJ Holowaychuk 创建和维护。

neoqs 未得到 qs 当前维护者的认可。


  • 🤌 3.9KB min+brotli(比 qs 小 3 倍)
  • 🚥 零依赖
  • 🎹 TypeScript。摒弃 @types/qs
  • ❎ 无 polyfills
  • 🛸 ESM 优先
  • 📜 支持 ES5 的传统模式

本包旨在遵循以下规则,并将长期坚持:

  • 无依赖。
  • 无 polyfills。
  • ESM 优先。
  • 力求现代化
  • 始终提供传统模式
  • 始终遵循 qs API。已经有许多包做到了这一点。neoqs 旨在成为 qs 的直接替代品,提供相同的 API,但零依赖并改善开发者体验。

何时使用本包?

本包旨在成为 qs 的直接替代品,提供相同的 API,但零依赖并改善开发者体验。因此,如果你的项目中已经在使用 qs,你应该使用本包来替代。

何时使用本包?

如果你的用例非常简单(foo=bar&baz=baka),主要是顶层键(foo=bar),且不需要支持非常旧的浏览器和 Node 版本,那么从你的项目中删除 qsneoqs,改用 URLSearchParams

使用哪个构建版本?

neoqs 提供两个构建版本:

  • 默认版:向后兼容 qs 并提供相同的 API,但仅支持 ESM,编译为 ES2022,适用于 Node 18+
  • 传统版:ES5 和 CommonJS 的传统构建,兼容 qs 并提供相同的 API。理论上可以支持到 Node 4.0.0,但未经测试。

以下是不同构建版本的对比矩阵:

构建版本ESMCJS浏览器NodePolyfills大小
默认版✅ ES20223.9KB min+brotli
传统版✅ ES54.2KB min+brotli

如果你:

正在发布一个支持 CommonJS 的库:

使用 传统版 构建以兼容旧浏览器和 Node 版本。

const { parse, stringify } = require('neoqs/legacy');

ESM:

import { parse, stringify } from 'neoqs/legacy';

不关心旧浏览器或 Node 版本:

使用默认构建以避免破坏性变更,并获得更好的开发者体验。

import * as qs from 'neoqs';

const obj = qs.parse('a=c');
console.log(obj);

const str = qs.stringify(obj);
console.log(str);

关心旧浏览器或 Node 或 CommonJS 版本:

使用传统构建以兼容旧浏览器和 Node 版本。

const { parse, stringify } = require('neoqs/legacy');

ESM:

import { parse, stringify } from 'neoqs/legacy';

使用方法

import * as qs from 'neoqs';

const obj = qs.parse('a=c');
console.log(obj);

const str = qs.stringify(obj);
console.log(str);

解析对象

parse(string, [options]);

qs 允许你在查询字符串中创建嵌套对象,方法是用方括号 [] 包围子键的名称。例如,字符串 'foo[bar]=baz' 会转换为:

console.log(qs.parse('foo[bar]=baz'));
// 输出:
// {
//  foo: {
//    bar: 'baz'
//  }
//});

当使用 plainObjects 选项时,解析后的值会以空对象的形式返回,通过 Object.create(null) 创建,因此你应该注意,原型方法不会存在于其上,用户可以将这些名称设置为任何他们喜欢的值:

const nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });
console.log(nullObject);
// 输出:
// {
//  a: {
//    hasOwnProperty: 'b'
//  }
// }

默认情况下,会忽略会覆盖对象原型属性的参数。如果你希望保留这些字段的数据,可以使用上面提到的 plainObjects,或将 allowPrototypes 设置为 true,这将允许用户输入覆盖这些属性。警告:启用此选项通常是一个坏主意,因为它可能会在尝试使用被覆盖的属性时导致问题。使用此选项时请务必小心。

const protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true });
console.log(protoObject);
// 输出:
// {
//  a: {
//    hasOwnProperty: 'b'
//  }
// }

URI 编码的字符串也可以正常工作:

console.log(qs.parse('a%5Bb%5D=c'));
// 输出:
// {
//  a: {
//    b: 'c'
//  }
// }

你也可以嵌套对象,如 'foo[bar][baz]=foobarbaz'

console.log(qs.parse('foo[bar][baz]=foobarbaz'));
// 输出:
// {
//  foo: {
//    bar: {
//      baz: 'foobarbaz'
//    }
//  }
// }

默认情况下,在嵌套对象时,qs 最多只会解析 5 层深度。这意味着如果你尝试解析像 'a[b][c][d][e][f][g][h][i]=j' 这样的字符串,你得到的对象将是:

const expected = {
  a: {
    b: {
      c: {
        d: {
          e: {
            f: {
              '[g][h][i]': 'j'
            }
          }
        }
      }
    }
  }
};
console.log(qs.stringify(expected));
// 输出:
// 'a[b][c][d][e][f][g][h][i]=j'

可以通过向 qs.parse(string, [options]) 传递 depth 选项来覆盖这个深度:

const deep = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
console.log(deep);
// 输出:
// {
//  a: {
//    b: {
//      '[c][d][e][f][g][h][i]': 'j'
//    }
//  }
// }

你可以使用 strictDepth 选项(默认为 false)配置 qs,使其在解析超过这个深度的嵌套输入时抛出错误:

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

深度限制有助于在使用 qs 解析用户输入时减少滥用,建议将其保持在一个合理的小数值。strictDepth 选项通过在超过限制时抛出错误来增加一层保护,允许你捕获和处理这些情况。

出于类似原因,默认情况下 qs 最多只会解析 1000 个参数。可以通过传递 parameterLimit 选项来覆盖这个限制:

const limited = qs.parse('a=b&c=d', { parameterLimit: 1 });
console.log(limited);
// 输出:
// {
//  a: 'b'
// }

要忽略开头的问号,可以使用 ignoreQueryPrefix

const prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });
console.log(prefixed);
// 输出:
// {
//  a: 'b',
//  c: 'd'
// }

还可以传递一个可选的分隔符:

const delimited = qs.parse('a=b;c=d', { delimiter: ';' });
console.log(delimited);
// 输出:
// {
//  a: 'b',
//  c: 'd'
// }

分隔符也可以是正则表达式:

const regexed = qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ });
console.log(regexed);
// 输出:
// {
//  a: 'b',
//  c: 'd',
//  e: 'f'
// }

可以使用 allowDots 选项来启用点号表示法:

const withDots = qs.parse('a.b=c', { allowDots: true });
console.log(withDots);
// 输出:
// {
//  a: {
//    b: 'c'
//  }
// }

可以使用 decodeDotInKeys 选项来解码键中的点号。注意:这隐含了 allowDots,所以如果你将 decodeDotInKeys 设置为 true,而 allowDots 设置为 falseparse 将会报错。

const withDots = qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', {
  decodeDotInKeys: true
});
console.log(withDots);
// 输出:
// {
//  'name.obj': {
//    first: 'John',
//    last: 'Doe'
//  }
// }

可以使用allowEmptyArrays选项来允许对象中的空数组值

const withEmptyArrays = qs.parse('foo[]&bar=baz', { allowEmptyArrays: true });
console.log(withEmptyArrays);
// 输出:
// {
//  foo: [],
//  bar: 'baz'
// }

可以使用duplicates选项来更改遇到重复键时的行为

console.log(qs.parse('foo=bar&foo=baz', { duplicates: 'combine' }));
// 输出:
// {
//  foo: ['bar', 'baz']
// }

console.log(qs.parse('foo=bar&foo=baz', { duplicates: 'first' }));
// 输出:
// {
//  foo: 'bar'
// }

console.log(qs.parse('foo=bar&foo=baz', { duplicates: 'last' }));
// 输出:
// {
//  foo: 'baz'
// }

console.log(qs.parse('foo=bar&foo=baz', { duplicates: 'replace' }));
// 输出:
// {
//  foo: 'bar'
// }

如果您需要处理旧版浏览器或服务,还支持将百分比编码的八进制解码为iso-8859-1:

const oldCharset = qs.parse('a=%A7', { charset: 'iso-8859-1' });
console.log(oldCharset);
// 输出:
// {
//  a: '§'
// }

一些服务会在表单中添加一个初始的utf8=✓值,以便旧版Internet Explorer更有可能以utf-8提交表单。此外,服务器可以检查勾选标记字符的错误编码值,并检测查询字符串或application/x-www-form-urlencoded主体是否未以utf-8发送,例如,如果表单有accept-charset参数或包含页面有不同的字符集。

qs通过charsetSentinel选项支持此机制。如果指定,返回对象中将省略utf8参数。它将用于根据勾选标记的编码方式切换到iso-8859-1/utf-8模式。

重要:当您同时指定charset选项和charsetSentinel选项时,如果请求包含可以推断实际字符集的utf8参数,charset将被覆盖。在这种情况下,charset将作为默认字符集而不是权威字符集。

const detectedAsUtf8 = qs.parse('utf8=%E2%9C%93&a=%C3%B8', {
  charset: 'iso-8859-1',
  charsetSentinel: true
});
console.log(detectedAsUtf8);
// 输出:
// {
//  a: 'ø'
// }

// 浏览器在以iso-8859-1提交时将勾选标记编码为✓:
const detectedAsIso8859_1 = qs.parse('utf8=%26%2310003%3B&a=%F8', {
  charset: 'utf-8',
  charsetSentinel: true
});
console.log(detectedAsIso8859_1);
// 输出:
// {
//  a: 'ø'
// }

如果您想将&#...;语法解码为实际字符,您还可以指定interpretNumericEntities选项:

const detectedAsIso8859_1 = qs.parse('a=%26%239786%3B', {
  charset: 'iso-8859-1',
  interpretNumericEntities: true
});
console.log(detectedAsIso8859_1);
// 输出: {
//  a: '☺'
// }

charsetSentinel模式下检测字符集时,它也能正常工作。

解析数组

qs还可以使用类似的[]表示法解析数组:

const withArray = qs.parse('a[]=b&a[]=c');
console.log(withArray);
// 输出:
// {
//  a: ['b', 'c']
// }

您也可以指定索引:

const withIndexes = qs.parse('a[1]=c&a[0]=b');
console.log(withIndexes);
// 输出:
// {
//  a: ['b', 'c']
// }

请注意,数组中的索引和对象中的键之间的唯一区别是方括号之间的值必须是数字才能创建数组。在创建具有特定索引的数组时,qs将压缩稀疏数组,只保留现有值并保持它们的顺序:

const noSparse = qs.parse('a[1]=b&a[15]=c');
console.log(noSparse);
// 输出:
// {
//  a: ['b', 'c']
// }

您也可以使用allowSparse选项来解析稀疏数组:

const sparseArray = qs.parse('a[1]=2&a[3]=5', { allowSparse: true });
console.log(sparseArray);
// 输出:
// {
//  a: [, '2', , '5']
// }

请注意,空字符串也是一个值,并且会被保留:

const withEmptyString = qs.parse('a[]=&a[]=b');
console.log(withEmptyString);
// 输出:
// {
//  a: ['', 'b']
// }

const withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c');
console.log(withIndexedEmptyString);
// 输出:
// {
//  a: ['b', '', 'c']
// }

qs还会将数组中指定的索引限制为最大索引20。任何索引大于20的数组成员将转换为以索引为键的对象。这是为了处理有人发送例如a[999999999]的情况,遍历这个巨大的数组将花费大量时间。

const withMaxIndex = qs.parse('a[100]=b');
console.log(withMaxIndex);
// 输出:
// {
//  a: {
//    100: 'b'
//  }
// }

可以通过传递arrayLimit选项来覆盖此限制:

const withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 });
console.log(withArrayLimit);
// 输出:
// {
//  a: {
//    1: 'b'
//  }
// }

要完全禁用数组解析,请将parseArrays设置为false

const noParsingArrays = qs.parse('a[]=b', { parseArrays: false });
console.log(noParsingArrays);
// 输出:
// {
//  a: {
//    0: 'b'
//  }
// }

如果您混合使用不同的表示法,qs会将两个项目合并为一个对象:

const mixedNotation = qs.parse('a[0]=b&a[b]=c');
console.log(mixedNotation);
// 输出:
// {
//  a: {
//    0: 'b',
//    b: 'c'
//  }
// }

您还可以创建对象数组:

const arraysOfObjects = qs.parse('a[][b]=c');
console.log(arraysOfObjects);
// 输出:
// {
//  a: [{ b: 'c' }]
// }

有些人使用逗号连接数组,qs可以解析它:

const arraysOfObjects = qs.parse('a=b,c', { comma: true });
console.log(arraysOfObjects);
// 输出:
// {
//  a: ['b', 'c']
// }

这无法转换嵌套对象,例如a={b:1},{c:d}

解析原始/标量值(数字、布尔值、null等)

默认情况下,所有值都被解析为字符串。这种行为不会改变,并在问题#91中进行了解释。

const primitiveValues = qs.parse('a=15&b=true&c=null');
console.log(primitiveValues);
// 输出:
// {
//  a: '15',
//  b: 'true',
//  c: 'null'
// }

如果您希望自动将看起来像数字、布尔值和其他值的值转换为它们的原始对应项,您可以使用query-types Express JS中间件,它将自动转换所有请求查询参数。

字符串化

qs.stringify(object, [options]);

在字符串化时,qs默认对输出进行URI编码。对象按照您期望的方式进行字符串化:

console.log(qs.stringify({ a: 'b' }));
// 输出:
// a=b

console.log(qs.stringify({ a: { b: 'c' } }));
// 输出:
// a%5Bb%5D=c

可以通过将encode选项设置为false来禁用此编码:

const unencoded = qs.stringify({ a: { b: 'c' } }, { encode: false });
console.log(unencoded);
// 输出:
// a[b]=c

可以通过将encodeValuesOnly选项设置为true来禁用对键的编码:

const encodedValues = qs.stringify(
  { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
  { encodeValuesOnly: true }
);
console.log(encodedValues);
// 输出:
// a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h

这种编码也可以通过设置encoder选项为自定义编码方法来替换:

const encoded = qs.stringify(
  { a: { b: 'c' } },
  {
    encoder: function (str) {
      // 传入的值为 `a`、`b`、`c`
      return; // 返回编码后的字符串
    }
  }
);

(注意:如果 encodefalse,则 encoder 选项不适用)

encoder 类似,parse 方法也有一个 decoder 选项,用于覆盖属性和值的解码:

const decoded = qs.parse('x=z', {
  decoder: function (str) {
    // 传入的值为 `x`、`z`
    return; // 返回解码后的字符串
  }
});

你可以使用提供给编码器的类型参数,对键和值使用不同的逻辑进行编码:

const encoded = qs.stringify(
  { a: { b: 'c' } },
  {
    encoder: function (str, defaultEncoder, charset, type) {
      if (type === 'key') {
        return; // 编码后的键
      } else if (type === 'value') {
        return; // 编码后的值
      }
    }
  }
);

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

const decoded = qs.parse('x=z', {
  decoder: function (str, defaultDecoder, charset, type) {
    if (type === 'key') {
      return; // 解码后的键
    } else if (type === 'value') {
      return; // 解码后的值
    }
  }
});

为了清晰起见,此后的示例将展示未经 URI 编码的输出。请注意,在实际使用中,这些返回值将会被 URI 编码。

当数组被字符串化时,它们会遵循 arrayFormat 选项,默认为 indices

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

你可以通过将 indices 选项设置为 false 来覆盖此行为,或者更明确地将 arrayFormat 选项设置为 repeat

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

你可以使用 arrayFormat 选项来指定输出数组的格式:

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'

注意:当使用 arrayFormat 设置为 'comma' 时,你还可以将 commaRoundTrip 选项设置为 truefalse,以在单项数组上附加 [],使其能够通过解析进行往返传输。

当对象被字符串化时,默认使用方括号表示法:

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

你可以通过将 allowDots 选项设置为 true 来覆盖此行为,使用点表示法:

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

你可以通过将 encodeDotInKeys 选项设置为 true 来对对象键中的点进行编码:注意:这隐含了 allowDots,所以如果你将 decodeDotInKeys 设置为 true,而 allowDots 设置为 falsestringify 将会报错。注意:当 encodeValuesOnlytrueencodeDotInKeys 也为 true 时,只有键中的点会被编码,其他内容不会被编码。

qs.stringify(
  { 'name.obj': { first: 'John', last: 'Doe' } },
  { allowDots: true, encodeDotInKeys: true }
);
// 输出: 'name%252Eobj.first=John&name%252Eobj.last=Doe'

你可以通过将 allowEmptyArrays 选项设置为 true 来允许空数组值:

qs.stringify({ foo: [], bar: 'baz' }, { allowEmptyArrays: true });
// 输出: 'foo[]&bar=baz'

空字符串和 null 值将省略值,但等号 (=) 保留:

console.log(qs.stringify({ a: '' }));
// 输出:
// a=

没有值的键(如空对象或数组)将不返回任何内容:

console.log(qs.stringify({ a: [] }));
// 输出:
// ''

console.log(qs.stringify({ a: {} }));
// 输出:
// ''

console.log(qs.stringify({ a: [{}] }));
// 输出:
// ''

console.log(qs.stringify({ a: { b: [] } }));
// 输出:
// ''

console.log(qs.stringify({ a: { b: {} } }));
// 输出:
// ''

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

console.log(qs.stringify({ a: null, b: undefined }));
// 输出:
// a=

查询字符串可以选择在前面加上问号:

console.log(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }));
// 输出:
// ?a=b&c=d

分隔符也可以在 stringify 中被覆盖:

console.log(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }));
// 输出:
// a=b;c=d

如果你只想覆盖 Date 对象的序列化,可以提供一个 serializeDate 选项:

const date = new Date(7);
console.log(qs.stringify({ a: date }));
// 输出:
// a=1970-01-01T00:00:00.007Z

console.log(
  qs.stringify(
    { a: date },
    {
      serializeDate: function (d) {
        return d.getTime();
      }
    }
  )
);
// 输出:
// a=7

你可以使用 sort 选项来影响参数键的顺序:

function alphabeticalSort(a, b) {
  return a.localeCompare(b);
}
console.log(qs.stringify({ a: 'c', z: 'y', b: 'f' }, { sort: alphabeticalSort }));
// 输出:
// a=c&b=f&z=y

最后,你可以使用 filter 选项来限制哪些键将被包含在字符串化的输出中。如果你传递一个函数,它将为每个键调用以获取替换值。否则,如果你传递一个数组,它将用于选择要字符串化的属性和数组索引:

function filterFunc(prefix, value) {
  if (prefix == 'b') {
    // 返回 `undefined` 值以省略属性。
    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'

你也可以使用 filter 为用户定义的类型注入自定义序列化。假设你正在使用一个 API,它期望范围的查询字符串格式如下:

https://domain.com/endpoint?range=30...70

你可以将其建模为:

class Range {
  constructor(from, to) {
    this.from = from;
    this.to = to;
  }
}

你可以注入一个自定义序列化器来处理此类型的值:

qs.stringify(
  {
    range: new Range(30, 70)
  },
  {
    filter: (prefix, value) => {
      if (value instanceof Range) {
        return `${value.from}...${value.to}`;
      }
      // 以常规方式序列化
      return value;
    }
  }
);
// range=30...70

处理 null

默认情况下,null 值被视为空字符串:

const withNull = qs.stringify({ a: null, b: '' });
console.log(withNull);
// 输出:
// a=&b=1

解析时不区分有等号和无等号的参数。两者都被转换为空字符串。

const equalsInsensitive = qs.parse('a&b=');
console.log(equalsInsensitive);
// 输出:
// {
//  a: '',
//  b: ''
// }

要区分 null 值和空字符串,请使用 strictNullHandling 标志。在结果字符串中,null 值没有 = 符号:

const strictNull = qs.stringify({ a: null, b: '' }, { strictNullHandling: true });
console.log(strictNull);
// 输出:
// a&b=

要将没有=的值解析回null,请使用strictNullHandling标志:

const parsedStrictNull = qs.parse('a&b=', { strictNullHandling: true });
console.log(parsedStrictNull);
// 输出:
// {
//  a: null,
//  b: ''
// }

要完全跳过渲染值为null的键,请使用skipNulls标志:

const nullsSkipped = qs.stringify({ a: 'b', c: null }, { skipNulls: true });
console.log(nullsSkipped);
// 输出:
// a=b

如果您正在与遗留系统通信,可以使用charset选项切换到iso-8859-1

const iso = qs.stringify({ æ: 'æ' }, { charset: 'iso-8859-1' });
console.log(iso);
// 输出:
// %E6=%E6

iso-8859-1中不存在的字符将被转换为数字实体,类似于浏览器的处理方式:

const numeric = qs.stringify({ a: '☺' }, { charset: 'iso-8859-1' });
console.log(numeric);
// 输出:
// a=%26%239786%3B

您可以使用charsetSentinel选项来通过包含一个utf8=✓参数来声明字符集,该参数使用正确的编码方式编码复选标记,类似于Ruby on Rails和其他框架在提交表单时的做法。

const sentinel = qs.stringify({ a: '☺' }, { charsetSentinel: true });
console.log(sentinel);
// 输出:
// utf8=%E2%9C%93&a=%E2%98%BA

const isoSentinel = qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' });
console.log(isoSentinel);
// 输出:
// utf8=%26%2310003%3B&a=%E6

处理特殊字符集

默认情况下,字符的编码和解码是以utf-8进行的,通过charset参数还内置了对iso-8859-1的支持。

如果您希望将查询字符串编码为不同的字符集(例如Shift JIS),可以使用qs-iconv库:

import qsEnvEncoder from 'qs-iconv/encoder';

const encoder = qsEnvEncoder('shift_jis');
const shiftJISEncoded = qs.stringify({ a: 'こんにちは!' }, { encoder: encoder });
console.log(shiftJISEncoded);
// 输出:
// a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I

这也适用于查询字符串的解码:

import qsEnvDecoder from 'qs-iconv/decoder';

const decoder = qsEnvDecoder('shift_jis');
const obj = qs.parse('a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I', { decoder: decoder });

console.log(obj);
// 输出:
// {
//  a: 'こんにちは!'
// }

RFC 3986和RFC 1738空格编码

RFC3986作为默认选项使用,将' '编码为_%20_,这是向后兼容的。同时,输出可以根据RFC1738进行字符串化,其中' '等同于'+'。

console.log(qs.stringify({ a: 'b c' }));
// 输出:
// a=b%20c

console.log(qs.stringify({ a: 'b c' }, { format: 'RFC3986' }));
// 输出:
// a=b%20c

console.log(qs.stringify({ a: 'b c' }, { format: 'RFC1738' }));
// 输出:
// a=b+c

安全性

如果您发现潜在的安全漏洞需要报告,请通过Twitter私信联系@puruvjdev

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号