JavaScript对象的查询字符串编码

719

有没有一种快速简单的方法将JavaScript对象编码为可以通过GET请求传递的string

不使用jQuery或其他框架,只需使用纯JavaScript :)


1
如果有合适的解决方案,为什么不能使用jQuery呢? - eaglei22
5
因为当时我正在为一款IPTV机顶盒设备开发项目工作,不允许使用外部库。;-) - napolux
1
感谢回复。我经常看到这个规范,一直想知道何时会使用。现在,我有一个例子了,谢谢! :) - eaglei22
24
因为有时候你不想加载一个庞大的库来获取一个id元素。 - Aaron Butacov
我制作了一个用于将JSON转换为HTTPs查询的网站:https://kshitijdhyani.com/JSONtoHTTPSerializer/ 希望对你有所帮助。 - Kshitij Dhyani
显示剩余3条评论
49个回答

12
如果需要发送任意对象,则使用GET方法不是一个好的选择,因为用户代理和Web服务器接受URL长度有限制。我的建议是构建一个名值对数组来发送数据,然后构建查询字符串:
function QueryStringBuilder() {
    var nameValues = [];

    this.add = function(name, value) {
        nameValues.push( {name: name, value: value} );
    };

    this.toQueryString = function() {
        var segments = [], nameValue;
        for (var i = 0, len = nameValues.length; i < len; i++) {
            nameValue = nameValues[i];
            segments[i] = encodeURIComponent(nameValue.name) + "=" + encodeURIComponent(nameValue.value);
        }
        return segments.join("&");
    };
}

var qsb = new QueryStringBuilder();
qsb.add("veg", "cabbage");
qsb.add("vegCount", "5");

alert( qsb.toQueryString() );

7
一点点变得更好。
objectToQueryString(obj, prefix) {
    return Object.keys(obj).map(objKey => {
        if (obj.hasOwnProperty(objKey)) {
            const key = prefix ? `${prefix}[${objKey}]` : objKey;
            const value = obj[objKey];

            return typeof value === "object" ?
                this.objectToQueryString(value, key) :
                `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
        }

        return null;
    }).join("&");
}

7

以下是被采纳答案的CoffeeScript版本。

serialize = (obj, prefix) ->
  str = []
  for p, v of obj
    k = if prefix then prefix + "[" + p + "]" else p
    if typeof v == "object"
      str.push(serialize(v, k))
    else
      str.push(encodeURIComponent(k) + "=" + encodeURIComponent(v))

  str.join("&")

7

使用:

const toQueryString = obj => "?".concat(Object.keys(obj).map(e => `${encodeURIComponent(e)}=${encodeURIComponent(obj[e])}`).join("&"));

const data = {
  offset: 5,
  limit: 10
};

toQueryString(data); // => ?offset=5&limit=10

或使用预定义功能

const data = {
  offset: 5,
  limit: 10
};

new URLSearchParams(data).toString(); // => ?offset=5&limit=10

注意

如果未出现在上述方法中,它们都会将值设置为 null。 如果您希望在值为 null 时不设置查询参数,则使用以下方法:

const toQueryString = obj => "?".concat(Object.keys(obj).map(e => obj[e] ? `${encodeURIComponent(e)}=${encodeURIComponent(obj[e])}` : null).filter(e => !!e).join("&"));


const data = {
  offset: null,
  limit: 10
};

toQueryString(data); // => "?limit=10" else with above methods "?offset=null&limit=10"

您可以自由使用任何方法。


1
URLSearchParams 应该是历史上唯一的答案。设置 value == null 是因为它始终会一致地评估为 falsey。这使得服务端点可以一致地检查参数值是否为 truthy 或 falsey,而无需进行额外的检查,这些检查涉及长度为 0 的字符串或未定义的字符串。您排除 null 值的解决方案是有效的,但我认为在大多数情况下,将 null 值保留在那里是更好的设计模式,因为大多数 API 在大多数情况下都会检查它们。 - Wes

7
这个函数会跳过空的或未定义的值。
export function urlEncodeQueryParams(data) {
    const params = Object.keys(data).map(key => data[key] ? `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}` : '');
    return params.filter(value => !!value).join('&');
}

6

这里是一个简洁且递归的版本,使用Object.entries。它可以处理任意嵌套的数组,但不能处理嵌套的对象。同时也会删除空元素:

const format = (k,v) => v !== null ? `${k}=${encodeURIComponent(v)}` : ''

const to_qs = (obj) => {
    return [].concat(...Object.entries(obj)
                       .map(([k,v]) => Array.isArray(v) 
                          ? v.map(arr => to_qs({[k]:arr})) 
                          : format(k,v)))
           .filter(x => x)
           .join('&');
}

E.g.:

let json = { 
    a: [1, 2, 3],
    b: [],              // omit b
    c: 1,
    d: "test&encoding", // uriencode
    e: [[4,5],[6,7]],   // flatten this
    f: null,            // omit nulls
    g: 0
};

let qs = to_qs(json)

=> "a=1&a=2&a=3&c=1&d=test%26encoding&e=4&e=5&e=6&e=7&g=0"

这个版本在处理嵌套数组时对我很有帮助。稍微调整了一下,使用了 Ruby/PHP 风格的数组键,但是除此之外都很好用。 - nickb

5

我有一个更简单的解决方案,不使用任何第三方库,并且已经适用于任何具有“Object.keys”(即所有现代浏览器+Edge + Internet Explorer)的浏览器:

ES5

function(a){
    if( typeof(a) !== 'object' )
        return '';
    return `?${Object.keys(a).map(k=>`${k}=${a[k]}`).join('&')}`;
}

ES3

function(a){
    if( typeof(a) !== 'object' )
        return '';
    return '?' + Object.keys(a).map(function(k){ return k + '=' + a[k] }).join('&');
}

5

我做了一个JSON字符串化器的比较,结果如下:

JSON:    {"_id":"5973782bdb9a930533b05cb2","isActive":true,"balance":"$1,446.35","age":32,"name":"Logan Keller","email":"logankeller@artiq.com","phone":"+1 (952) 533-2258","friends":[{"id":0,"name":"Colon Salazar"},{"id":1,"name":"French Mcneil"},{"id":2,"name":"Carol Martin"}],"favoriteFruit":"banana"}
Rison:   (_id:'5973782bdb9a930533b05cb2',age:32,balance:'$1,446.35',email:'logankeller@artiq.com',favoriteFruit:banana,friends:!((id:0,name:'Colon Salazar'),(id:1,name:'French Mcneil'),(id:2,name:'Carol Martin')),isActive:!t,name:'Logan Keller',phone:'+1 (952) 533-2258')
O-Rison: _id:'5973782bdb9a930533b05cb2',age:32,balance:'$1,446.35',email:'logankeller@artiq.com',favoriteFruit:banana,friends:!((id:0,name:'Colon Salazar'),(id:1,name:'French Mcneil'),(id:2,name:'Carol Martin')),isActive:!t,name:'Logan Keller',phone:'+1 (952) 533-2258'
JSURL:   ~(_id~'5973782bdb9a930533b05cb2~isActive~true~balance~'!1*2c446.35~age~32~name~'Logan*20Keller~email~'logankeller*40artiq.com~phone~'*2b1*20*28952*29*20533-2258~friends~(~(id~0~name~'Colon*20Salazar)~(id~1~name~'French*20Mcneil)~(id~2~name~'Carol*20Martin))~favoriteFruit~'banana)
QS:      _id=5973782bdb9a930533b05cb2&isActive=true&balance=$1,446.35&age=32&name=Logan Keller&email=logankeller@artiq.com&phone=+1 (952) 533-2258&friends[0][id]=0&friends[0][name]=Colon Salazar&friends[1][id]=1&friends[1][name]=French Mcneil&friends[2][id]=2&friends[2][name]=Carol Martin&favoriteFruit=banana
URLON:   $_id=5973782bdb9a930533b05cb2&isActive:true&balance=$1,446.35&age:32&name=Logan%20Keller&email=logankeller@artiq.com&phone=+1%20(952)%20533-2258&friends@$id:0&name=Colon%20Salazar;&$id:1&name=French%20Mcneil;&$id:2&name=Carol%20Martin;;&favoriteFruit=banana
QS-JSON: isActive=true&balance=%241%2C446.35&age=32&name=Logan+Keller&email=logankeller%40artiq.com&phone=%2B1+(952)+533-2258&friends(0).id=0&friends(0).name=Colon+Salazar&friends(1).id=1&friends(1).name=French+Mcneil&friends(2).id=2&friends(2).name=Carol+Martin&favoriteFruit=banana

其中最短的是 URL Object Notation

5

还有另一个流行的库qs。你可以通过以下方式添加它:

yarn add qs

然后像这样使用它:

import qs from 'qs'

const array = { a: { b: 'c' } }
const stringified = qs.stringify(array, { encode: false })

console.log(stringified) //-- outputs a[b]=c

1
这是因为原帖作者想要使用纯JavaScript,没有外部库。 - Epic Speedy

4
将对象转换为查询字符串的单行代码,以便将来需要时使用:
let Objs = { a: 'obejct-a', b: 'object-b' }

Object.keys(objs).map(key => key + '=' + objs[key]).join('&')

// The result will be a=object-a&b=object-b

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接