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

在Javascript中将对象文字编码为URL查询字符串,javascript,jquery,ajax,query-string,Javascript,Jquery,Ajax,Query String,我试图在项目中摆脱jQuery依赖关系。project所做的一件事是将数据发布到服务器,如下所示: var data = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"}; $.post( url, data); 感谢,我知道如何使用XMLHttpRequest在纯Javascript中重写$。post: var request = new XMLHttpRequest(); reques

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

var data = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};
$.post( url, data);
感谢,我知道如何使用
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);
不幸的是,这个描述似乎假设
数据
对象已经是一个URL编码的查询字符串,这显然不是上面示例中的情况。事实证明jQuery的作用不止于此:对于给定的
数据
对象,上面的
$.post
调用将首先将其转换为查询字符串,如下所示:

apple%5B0%5D%5Bkiwi%5D=orange&apple%5B1%5D%5Bbanana%5D=lemon&pear=passion+fruit
使用
XMLHttpRequest
的代码片段不会这样做,因此,服务器会向我抛出错误

jQuery还有一个很好的方法调用,它正好完成了这个转换。如果在最后一行中,使用
XMLHttpRequest
的上述代码片段将非常有效

request.send( $.param(data));
但是,我没有摆脱jQuery依赖。因此,我正在寻找一个纯Javascript等价物
$.param
。有人有这样的东西吗

注意:这个问题问了一个类似的问题,但公认的答案只适用于非常简单的情况。将该答案中给出的函数应用于我上面的
数据
对象会产生:

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

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

您可以继续执行递归代码,但为什么不尝试简单的JSON方案呢?这就是为什么创建JSON的原因,它可以更轻松地在客户端和服务器之间交换数据

就这么做吧

request.send(JSON.stringify(data));
JSON.stringify
接受一个对象,然后该对象将被转换为有效的JSON,可以在服务器端进行解析


要了解更多关于JSON的信息,最好的方法莫过于查看它的标记摘录

您可以使用encode和decode组件函数来实现这一点

编辑 那么这个呢:

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"}

我已经为您制作了一个快速函数,应该可以为您实现这一点,它将从您的key=>value对创建参数,并将您的非基本值字符串化

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

Edit,从您的评论来看,这应该有效,现在与$的输出相匹配。参数:


谢谢你的回答。我知道JSON,但不幸的是,我可以自由修改客户端代码,但不能修改服务器端代码。服务器需要一个查询字符串而不是JSON字符串,因此我需要一个将对象转换为查询字符串的函数,如
$。param
需要。您是否尝试仅提取jquery.param的源代码@里卡多卡斯塔涅达:这可能是最好的主意。我曾希望有一个更直接的解决办法。从jQuery中提取的代码将是完美的答案,我会立即接受;-)(这也将是一个伟大的补充)。我想我会看一看。我已经用代码添加了一个答案,如果这不是正确的来源,你可以编辑这篇文章。谢谢Simon,但这似乎并不完全正确。如果附加
console.log($.param(数据))
在小提琴的末尾(需要jQuery),您将看到
$的输出。param
是不同的。我尝试了你的代码,但不幸的是,如果我发送你函数的输出,我的服务器会阻塞。我喜欢你的方法!非常好的代码。我只是变得懒惰,把我最初的答案胡乱编造成我认为需要的答案PI最终提取了jQuery源代码,但感谢您的帮助。:)@Todd很抱歉,如果我不完全清楚我想要什么,我认为“做
$.param
做的事”足够精确,我试图给出一些上下文,但可能会导致混淆。stringifyParam的实现中有一个错误:“if(topLevel[key]){string+=key;}”应该替换为“if(topLevel[key]!=undefined”){string+=key;}因为0(零)是一个值!:)我担心还有另一个错误:调用
toParam({var:{foo:bar,baz:qux});
得到我
var%5Bfoo%5D=bar&%5Bbaz%5D=qux
它解码为
var[foo]=bar&[baz]=qux
,即第二个
var[]
部分缺失。关于您的编辑:它仍然与
$.param(data)
不同。如上所述,预期的输出将是
apple%5B0%5D%5Bkiwi%5D=橙色和苹果%5B1%5D%5bana%5D=柠檬和梨=西番莲+水果
(即
apple[0][kiwi=橙色和苹果[1][香蕉]=柠檬和梨=西番莲水果
,URL解码格式).您的函数或多或少会对一个JSON字符串进行URL编码,这是不同的。
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