在 Javascript 中将对象文本编码为 URL 查询字符串

Encode object literal as URL query string in Javascript

本文关键字:URL 查询 字符串 编码 文本 Javascript 对象      更新时间:2023-09-26

我正在尝试摆脱项目中的jQuery依赖关系。该项目做的一件事是将数据发布到服务器,如下所示:

var data = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};
$.post( url, data);

感谢你可能不需要jQuery,我知道如何使用XMLHttpRequest用纯Javascript重写$.post

var request = new XMLHttpRequest();
request.open( 'POST', url, true);
request.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.send( data);

不幸的是,此描述似乎假定 data 对象已经是 URL 编码的查询字符串,而上面的示例中显然不是这种情况。事实证明,jQuery所做的远不止于此:对于给定的data对象,上面的$.post调用将首先将其转换为查询字符串,如下所示:

apple%5B0%5D%5Bkiwi%5D=orange&apple%5B1%5D%5Bbanana%5D=lemon&pear=passion+fruit

使用 XMLHttpRequest 的代码片段不会这样做,因此,服务器会向我抛出错误。

jQuery还有一个很棒的方法调用$.param它正是执行此转换的。如果我在最后一行这样做,上面使用 XMLHttpRequest 的代码片段将非常有效

request.send( $.param(data));

但是,我并没有摆脱jQuery依赖。所以我正在寻找一个纯粹的Javascript等同于$.param。有人有这样的东西吗?

注意:问题 jQuery.param() 的 Plain Javascript 等效性提出了类似的问题,但接受的答案仅适用于非常简单的情况。将该答案中给出的函数应用于我的上述data对象会产生:

apple=%5Bobject%20Object%5D%2C%5Bobject%20Object%5D&pear=passion%20fruit

。这显然与上面给出的$.param(data)结果不同,并且由于它不以递归方式工作而丢失信息。

我为您制作了一个快速函数,应该为您实现这一点,它将从您的键=>值对创建参数并字符串化您的非原始值。

var objToParams = function(obj){
    var paramString = '';
    for (var key in data) {
        var value = obj[key];
        if(obj[key] instanceof Array || obj[key] instanceof Object){
            value = encodeURIComponent(JSON.stringify(value));
        }
        if (paramString != "") paramString += "&";
        paramString += key + "=" + encodeURIComponent(value);
    }
    return paramString;
}
var data = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};
console.log(objToParams(data));

http://jsfiddle.net/7buy3rjy/

编辑,从您的评论中,这应该可以工作,现在与 $.param 的输出匹配:

http://jsfiddle.net/mg511z7w/

var data = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};
var stringifyParam = function(data, topLevel, keyProp) {
        var string = '';
        for (var key in data) {
            if(keyProp && topLevel[keyProp] ) {
                if ( (topLevel[keyProp] instanceof Array&&topLevel[keyProp].indexOf(data[key])!==0) ) {
                    string += keyProp;
                } else if ( (topLevel[keyProp] instanceof Object&&topLevel[keyProp][key]) ) {
                    string += keyProp;
                }
            }
            if (typeof(topLevel[key])=='undefined') {
                string += '[' + key + ']';
            }
            if (data[key] instanceof Array) {
                string += stringifyParam(data[key], topLevel, key);
            } else if(data[key] instanceof Object){
                string += stringifyParam(data[key], topLevel, key);            
            } else {
                if (typeof(topLevel[key])!='undefined') {
                    string += key;
                }
                string += '=' + data[key];
                string += '&';
            }
        }
        return string;
    },
    toParam = function(data){
        var string = stringifyParam(data,data);
        return encodeURI(string.substring(0,string.length-1).split(' ').join('+'));
    };
console.log(toParam(data)); //apple%5B0%5D%5Bkiwi%5D=orange&apple%5B1%5D%5Bbanana%5D=lemon&pear=passion+fruit
console.log($.param(data)); //apple%5B0%5D%5Bkiwi%5D=orange&apple%5B1%5D%5Bbanana%5D=lemon&pear=passion+fruit

你可以去做递归代码,但为什么不尝试简单的方案JSON,这就是它被创建的原因 - 以更简单的方式在客户端和服务器之间交换数据。

就这样做

request.send(JSON.stringify(data));

JSON.stringify接受一个对象,然后该对象将被转换为有效的 JSON,可以在服务器端解析。

要了解有关 JSON 的更多信息,没有比在此处浏览其标签摘录更好的方法

您可以使用

编码和解码URIComponent函数来完成此操作。

编辑

这个呢:

var qs = Object.keys(obj).reduce(function(a,k){
    a.push(k+'='+encodeURIComponent(JSON.stringify(obj[k])));
    return a;
},[]).join('&');
// "apple=%5B%7B%22kiwi%22%3A%22orange%22%7D%2C%7B%22banana%22%3A%22lemon%22%7D%5D&pear=%22passion%20fruit%22"

取而代之的是:

var obj = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};
var data = encodeURIComponent(JSON.stringify(obj));
// "%7B%22apple%22%3A%5B%7B%22kiwi%22%3A%22orange%22%7D%2C%7B%22banana%22%3A%22lemon%22%7D%5D%2C%22pear%22%3A%22passion%20fruit%22%7D"
var obj2 = JSON.parse(decodeURIComponent(data));
// {"apple":[{"kiwi":"orange"},{"banana":"lemon"}],"pear":"passion fruit"}