将 JavaScript 对象转换为 URI 编码的字符串

70

我有一个 JavaScript 对象,希望将其转换为 x-www-form-urlencoded 格式。

类似于 $('#myform').serialize(),但是针对对象。

如下所示的对象:

{
    firstName: "Jonas",
    lastName: "Gauffin"
}

会被编码为:

firstName=Jonas&lastName=Gauffin(请注意,特殊字符应该得到适当的编码)


之前问过:http://stackoverflow.com/questions/3848340/is-there-a-better-way-to-convert-a-json-packet-into-a-query-string - Frank van Wijk
请提供一个输入和输出的示例。如果您只想编码JSON,encodeURIComponent(json) 应该就可以了。 - Felix Kling
12个回答

76

我很惊讶没有人提到URLSearchParams

var prms = new URLSearchParams({
  firstName: "Jonas",
  lastName: "Gauffin"
});
console.log(prms.toString());
// firstName=Jonas&lastName=Gauffin

3
应该肯定是被接受的答案。只要知道它还不能在IE中工作。查看CanIUse以了解是否已经改变:https://caniuse.com/#search=URLSearchParams - Eric Seastrand
让我们面对现实吧,仍在使用IE的奶奶们永远不会遇到如此复杂的应用程序。 - Moe

65

请仔细查看我在这里提供的两个答案,确定哪个最适合您。


答案1:

可能是您需要的:准备一个JSON以作为单个参数在URL中使用,以便稍后解码。

jsfiddle

encodeURIComponent(JSON.stringify({"test1":"val1","test2":"val2"}))+"<div>");

结果:

%7B%22test%22%3A%22val1%22%2C%22test2%22%3A%22val2%22%7D

对于那些只想要一个函数来完成这项任务的人:

function jsonToURI(json){ return encodeURIComponent(JSON.stringify(json)); }

function uriToJSON(urijson){ return JSON.parse(decodeURIComponent(urijson)); }

答案 2:

使用 JSON 作为键值对的来源,用于生成 x-www-form-urlencoded 格式的输出。

jsfiddle

// This should probably only be used if all JSON elements are strings
function xwwwfurlenc(srcjson){
    if(typeof srcjson !== "object")
      if(typeof console !== "undefined"){
        console.log("\"srcjson\" is not a JSON object");
        return null;
      }
    u = encodeURIComponent;
    var urljson = "";
    var keys = Object.keys(srcjson);
    for(var i=0; i <keys.length; i++){
        urljson += u(keys[i]) + "=" + u(srcjson[keys[i]]);
        if(i < (keys.length-1))urljson+="&";
    }
    return urljson;
}

// Will only decode as strings
// Without embedding extra information, there is no clean way to
// know what type of variable it was.
function dexwwwfurlenc(urljson){
    var dstjson = {};
    var ret;
    var reg = /(?:^|&)(\w+)=(\w+)/g;
    while((ret = reg.exec(urljson)) !== null){
        dstjson[ret[1]] = ret[2];
    }
    return dstjson;
}

2
这应该是标准答案。不知道为什么没有人点赞。 - Monarch Wadia
17
因为它不是作为x-www-form-urlencoded(键值对)进行编码。 - jgauffin
已更新以包含原先请求的编码的答案。 - Grallen

22

请参见jQuery.param(...)。将转换为uri,有关更多信息,请参见链接!


22

由于您要求一个序列化对象,所以这可能略有偏差。但是以防万一,如果您的意图是将该对象中的值用作单个参数,则这可能是您要寻找的转换:

var params = {
    "param1": "arg1",
    "param2": "arg2"
};
var query = "";
for (key in params) {
    query += encodeURIComponent(key)+"="+encodeURIComponent(params[key])+"&";
}
xmlhttp.send(query);

理论上很好,唯一的问题是最后总会有一个尾随的“&”。我使用了非常类似的方法,但是我设置了数组值,然后使用join("&")。效果很好。 - SuperJumpBros

4

与以上代码具有相同效果,但函数式风格可以提供更优雅的表达:

const to_encoded = obj => Object.keys(obj).map(k =>
    `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`).join('&');

const toEncoded = (obj: { [key: string]: string }) => 保持 TypeScript 的兼容性 - ryanrain
你是否想知道为什么无法将整个合并的字符串传递给encodeURIComponent(...join('&'))呢???MDN文档让你相信这是可行的...https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent - mattdlockyer

4
@Grallen的答案1扩展 - 如果您需要更短的URL:
输入:
{"q":"SomethingTM","filters":[{"kind":"A","q":"foobar"},{"kind":"B","isntIt":true}],"pagenumber":1}

输出:

('q'~'SomethingTM'_'filters'~!('kind'~'A'_'q'~'foobar')_('kind'~'B'_'isntIt'~true)*_'pagenumber'~1)

改为:

%7B%22q%22%3A%22SomethingTM%22%2C%22filters%22%3A%5B%7B%22kind%22%3A%22A%22%2C%22q%22%3A%22foobar%22%7D%2C%7B%22kind%22%3A%22B%22%2C%22isntIt%22%3Atrue%7D%5D%2C%22pagenumber%22%3A1%7D

function jsonToUri(v, r, s) {
  return encodeURIComponent(
    JSON.stringify(v, r, s)
    .replace(/[()'~_!*]/g, function(c) {
      // Replace ()'~_!* with \u0000 escape sequences
      return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4)
    })
    .replace(/\{/g, '(')    //    { -> (
    .replace(/\}/g, ')')    //    } -> )
    .replace(/"/g,  "'")    //    " -> '
    .replace(/\:/g, '~')    //    : -> ~
    .replace(/,/g,  '_')    //    , -> _
    .replace(/\[/g, '!')    //    [ -> !
    .replace(/\]/g, '*')    //    ] -> *
  )
}

function uriToJson(t, r) {
  return JSON.parse(
    decodeURIComponent(t)
    .replace(/\(/g, '{')    //    ( -> {
    .replace(/\)/g, '}')    //    ) -> }
    .replace(/'/g,  '"')    //    ' -> "
    .replace(/~/g,  ':')    //    ~ -> :
    .replace(/_/g,  ',')    //    _ -> ,
    .replace(/\!/g, '[')    //    ! -> [
    .replace(/\*/g, ']')    //    * -> ]
    , r
  )
}



//////// TESTS ////////



var a = {q: 'SomethingTM', filters: [{kind: 'A', q: 'foobar'}, {kind: 'B', isntIt: true}], pagenumber: 1}
var b = jsonToUri(a)
var c = uriToJson(b)

console.log(b)
// ('q'~'SomethingTM'_'filters'~!('kind'~'A'_'q'~'foobar')_('kind'~'B'_'isntIt'~true)*_'pagenumber'~1)

console.log(JSON.stringify(c))
// {"q":"SomethingTM","filters":[{"kind":"A","q":"foobar"},{"kind":"B","isntIt":true}],"pagenumber":1}

var a2 = {"q":"Something(TM)","filters":[{"kind":"A*","q":"foo_bar"},{"kind":"B!","isn'tIt":true}],"page~number":1}
var b2 = jsonToUri(a2)
var c2 = uriToJson(b2)

console.log(b2)
// ('q'~'Something%5Cu0028TM%5Cu0029'_'filters'~!('kind'~'A%5Cu002a'_'q'~'foo%5Cu005fbar')_('kind'~'B%5Cu0021'_'isn%5Cu0027tIt'~true)*_'page%5Cu007enumber'~1)

console.log(JSON.stringify(c2))
// {"q":"Something(TM)","filters":[{"kind":"A*","q":"foo_bar"},{"kind":"B!","isn'tIt":true}],"page~number":1}


3

需要注意的是,已接受的答案不包括对嵌套对象的支持。以下是一种实现方法:

function xwwwfurlenc(srcjson, parent=""){
    if(typeof srcjson !== "object")
      if(typeof console !== "undefined"){
        console.log("\"srcjson\" is not a JSON object");
        return null;
    }

    let u = encodeURIComponent;
    let urljson = "";
    let keys = Object.keys(srcjson);

    for(let i=0; i < keys.length; i++){
      let k = parent ? parent + "[" + keys[i] + "]" : keys[i];

      if(typeof srcjson[keys[i]] !== "object"){
        urljson += u(k) + "=" + u(srcjson[keys[i]]);
      } else {
        urljson += xwwwfurlenc(srcjson[keys[i]], k)
      }
      if(i < (keys.length-1))urljson+="&";
    }

    return urljson;
}

2
为了补充@Claymore的回答,这里有一个函数来编码一个对象并额外省略尾随的&符号:

构建方法如下:

encodeObject(params) {
  var query = [];
  for (let key in params) {
    let val = encodeURIComponent(key) + "=" + encodeURIComponent(params[key]);
    query.push(val);
  }
  return query.join('&');
}

1
function jsonToURI(jsonObj) {
    var output = '';
    var keys = Object.keys(jsonObj);
    keys.forEach(function(key) {
        output = output + key + '=' + jsonObj[key] + '&';
    })
    return output.slice(0, -1);
}

function uriToJSON(urijson) {
    var output = {};
    urijson = decodeURIComponent(urijson);
    urijson = urijson.split('&');
    urijson.forEach(function(param) {
        var param = param.split('=');
        output[param[0]] = param[1];
    })
    return output
}

0
创建一个函数来解析查询参数。

const parseQueryParams = (query) => {
  return Object.entries(query)
    .map(([key, value]) => key + '=' + encodeURIComponent(value))
    .join('&')
}


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