web-dev-qa-db-fra.com

Encodage par chaîne de requête d'un objet Javascript

Connaissez-vous un moyen simple et rapide de coder un objet Javascript dans une string que je peux transmettre via une requête GET?

Non jQuery, pas d'autres cadres - juste Javascript Javascript :)

387
Napolux

comme ça?

serialize = function(obj) {
  var str = [];
  for (var p in obj)
    if (obj.hasOwnProperty(p)) {
      str.Push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
    }
  return str.join("&");
}

console.log(serialize({
  foo: "hi there",
  bar: "100%"
}));
// foo=hi%20there&bar=100%25

Edit: celui-ci convertit également les objets récursifs (en utilisant la notation php "array" pour la chaîne de requête)

serialize = function(obj, prefix) {
  var str = [],
    p;
  for (p in obj) {
    if (obj.hasOwnProperty(p)) {
      var k = prefix ? prefix + "[" + p + "]" : p,
        v = obj[p];
      str.Push((v !== null && typeof v === "object") ?
        serialize(v, k) :
        encodeURIComponent(k) + "=" + encodeURIComponent(v));
    }
  }
  return str.join("&");
}

console.log(serialize({
  foo: "hi there",
  bar: {
    blah: 123,
    quux: [1, 2, 3]
  }
}));
// foo=hi%20there&bar%5Bblah%5D=123&bar%5Bquux%5D%5B0%5D=1&bar%5Bquux%5D%5B1%5D=2&bar%5Bquux%5D%5B2%5D=3

701
user187291

jQuery a une fonction pour cela, jQuery.param(), si vous l'utilisez déjà, vous pouvez l'utiliser: http://api.jquery.com/jquery.param/

exemple:

var params = { width:1680, height:1050 };
var str = jQuery.param( params );

str contient maintenant width=1680&height=1050

215
benvds
Object.keys(obj).reduce(function(a,k){a.Push(k+'='+encodeURIComponent(obj[k]));return a},[]).join('&')

Edit: J'aime ce one-line, mais je parie que ce serait une réponse plus populaire si elle correspondait sémantiquement à la réponse acceptée:

function serialize( obj ) {
  return '?'+Object.keys(obj).reduce(function(a,k){a.Push(k+'='+encodeURIComponent(obj[k]));return a},[]).join('&')
}
114
sergk

Voici un one-liner dans ES6:

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

Avec Node.js v6.6.3

const querystring = require('querystring')

const obj = {
  foo: 'bar',
  baz: 'tor'
}

let result = querystring.stringify(obj)
// foo=bar&baz=tor

Référence: https://nodejs.org/api/querystring.html

39

Je suggère d'utiliser le URLSearchParams interface:

const searchParams = new URLSearchParams();
const search = {foo: "hi there", bar: "100%" };
Object.keys(search).forEach(key => searchParams.append(key, search[key]));
console.log(searchParams.toString())
28
bmaggi

Un petit amendement à la solution acceptée par l'utilisateur187291:

serialize = function(obj) {
   var str = [];
   for(var p in obj){
       if (obj.hasOwnProperty(p)) {
           str.Push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
       }
   }
   return str.join("&");
}

La vérification de hasOwnProperty sur l'objet rend JSLint/JSHint heureux et évite la sérialisation accidentelle des méthodes de l'objet ou d'autres éléments si l'objet n'est pas un simple dictionnaire. Voir le paragraphe relatif aux déclarations sur cette page: http://javascript.crockford.com/code.html

23
jssebastian

Pouvez-vous utiliser URLSearchParams?

juste new URLSearchParams(object).toString()

Chrome 49+, bien que

13
nullaber

Rails/PHP Générateur de requêtes de styles

Cette méthode convertit un objet Javascript en URI Query String. Gère également les tableaux et objets imbriqués (dans la syntaxe Rails/PHP):

function serializeQuery(params, prefix) {
  const query = Object.keys(params).map((key) => {
    const value  = params[key];

    if (params.constructor === Array)
      key = `${prefix}[]`;
    else if (params.constructor === Object)
      key = (prefix ? `${prefix}[${key}]` : key);

    if (typeof value === 'object')
      return serializeQuery(value, key);
    else
      return `${key}=${encodeURIComponent(value)}`;
  });

  return [].concat.apply([], query).join('&');
}

Exemple d'utilisation:

let params = {
  a: 100,
  b: 'has spaces',
  c: [1, 2, 3],
  d: { x: 9, y: 8}
}

serializeQuery(params)
// returns 'a=100&b=has%20spaces&c[]=1&c[]=2&c[]=3&d[x]=9&d[y]=8
10
Sheharyar

Avez-vous besoin d'envoyer des objets arbitraires? Si tel est le cas, GET est une mauvaise idée car il existe des limites quant à la longueur des URL acceptées par les agents d'utilisateurs et les serveurs Web. Ma suggestion serait de constituer un tableau de paires nom-valeur à envoyer, puis de créer une chaîne de requête:

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() );
10
Tim Down

Voici la version coffeescript de la réponse acceptée. Cela pourrait faire gagner du temps à quelqu'un.

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("&")
9
alf

utilisez JSON.

jetez un oeil à cette question pour des idées sur la manière de les mettre en œuvre.

9
Ofri Raviv

Eh bien, tout le monde semble mettre son unique doublure ici, alors voici le mien:

const encoded = Object.entries(obj).map((k, v) => `${k}=${encodeURIComponent(v)}`).join("&");
8
Alex Escalante

Voici une version concise et récursive avec Object.entries . Il gère les tableaux imbriqués de manière arbitraire, mais pas les objets imbriqués. Il supprime également les éléments vides:

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

Par exemple.:

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"
6
mikebridge

Dans ES7, vous pouvez écrire ceci sur une ligne:

const serialize = (obj) => (Object.entries(obj).map(i => [i[0], encodeURIComponent(i[1])].join('=')).join('&'))
4
Pavlo Sadovyi

J'ai une solution plus simple qui n'utilise aucune bibliothèque tierce et qui est déjà susceptible d'être utilisée dans n'importe quel navigateur doté de "Object.keys" (tous les navigateurs modernes + Edge + ie):

Dans ES5

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

Dans ES3

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

J'ai fait une comparaison de stringifiers JSON et les résultats sont les suivants:

JSON:    {"_id":"5973782bdb9a930533b05cb2","isActive":true,"balance":"$1,446.35","age":32,"name":"Logan Keller","email":"[email protected]","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:'[email protected]',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:'[email protected]',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 protected]&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 protected]&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

Le plus court d'entre eux est URL Object Notation .

3
niutech

Si vous souhaitez convertir un objet imbriqué de manière récursive et que l'objet peut contenir ou non des tableaux (et que ceux-ci peuvent contenir des objets ou des tableaux, etc.), la solution devient un peu plus complexe. Ceci est ma tentative.

J'ai également ajouté des options pour choisir si vous souhaitez enregistrer pour chaque membre d'objet à quelle profondeur dans l'objet principal il se trouve, et pour choisir si vous souhaitez ajouter une étiquette aux membres provenant de tableaux convertis.

Idéalement, vous devriez vérifier si le paramètre chose reçoit réellement un objet ou un tableau.

function thingToString(thing,maxDepth,recordLevel,markArrays){
    //thing: object or array to be recursively serialized
    //maxDepth (int or false):
    // (int) how deep to go with converting objects/arrays within objs/arrays
    // (false) no limit to recursive objects/arrays within objects/arrays
    //recordLevel (boolean):
    //  true - insert "(level 1)" before transcript of members at level one (etc)
    //  false - just 
    //markArrays (boolean):
    //  insert text to indicate any members that came from arrays
    var result = "";
    if (maxDepth !== false && typeof maxDepth != 'number') {maxDepth = 3;}
    var runningDepth = 0;//Keeps track how deep we're into recursion

    //First prepare the function, so that it can call itself recursively
    function serializeAnything(thing){
        //Set path-Finder values
        runningDepth += 1;
        if(recordLevel){result += "(level " + runningDepth + ")";}

        //First convert any arrays to object so they can be processed
        if (thing instanceof Array){
            var realObj = {};var key;
            if (markArrays) {realObj['type'] = "converted array";}
            for (var i = 0;i < thing.length;i++){
                if (markArrays) {key = "a" + i;} else {key = i;}
                realObj[key] = thing[i];
            }
            thing = realObj;
            console.log('converted one array to ' + typeof realObj);
            console.log(thing);
        }

        //Then deal with it
        for (var member in thing){
            if (typeof thing[member] == 'object' && runningDepth < maxDepth){
                serializeAnything(thing[member]);
                //When a sub-object/array is serialized, it will add one to
                //running depth. But when we continue to this object/array's
                //next sibling, the level must go back up by one
                runningDepth -= 1;
            } else if (maxDepth !== false && runningDepth >= maxDepth) {
                console.log('Reached bottom');
            } else 
            if (
                typeof thing[member] == "string" || 
                typeof thing[member] == 'boolean' ||
                typeof thing[member] == 'number'
            ){
                result += "(" + member + ": " + thing[member] + ") ";
            }  else {
                result += "(" + member + ": [" + typeof thing[member] + " not supported]) ";
            }
        }
    }
    //Actually kick off the serialization
    serializeAnything(thing);

    return result;

}
3
Wytze

Celui-ci ignore les valeurs null/indéfinies

export function urlEncodeQueryParams(data) {
    const params = Object.keys(data).map(key => data[key] ? `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}` : '');
    return params.filter(value => !!value).join('&');
}
3
nimatra

Une seule ligne pour convertir l'objet en chaîne de requête au cas où quelqu'un en aurait de nouveau besoin

let Objs = { a: 'obejct-a', b: 'object-b' }

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

// result will be a=object-a&b=object-b
3
Laravel Plus

Un peu mieux

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("&");
}
3
Pavel

Ajout pour la solution acceptée, cela fonctionne avec les objets et le tableau d'objets:

parseJsonAsQueryString = function (obj, prefix, objName) {
    var str = [];
    for (var p in obj) {
        if (obj.hasOwnProperty(p)) {
            var v = obj[p];
            if (typeof v == "object") {
                var k = (objName ? objName + '.' : '') + (prefix ? prefix + "[" + p + "]" : p);
                str.Push(parseJsonAsQueryString(v, k));
            } else {
                var k = (objName ? objName + '.' : '') + (prefix ? prefix + '.' + p : p);
                str.Push(encodeURIComponent(k) + "=" + encodeURIComponent(v));
                //str.Push(k + "=" + v);
            }
        }
    }
    return str.join("&");
}

Vous avez également ajouté objName si vous utilisez des paramètres d'objet, comme dans les méthodes d'action asp.net mvc.

3
A.Aziem Moemen

Les réponses ci-dessus ne répondent pas correctement si vous avez beaucoup d'objets imbriqués ..__ Vous pouvez plutôt choisir la fonction param à partir d'ici - https://github.com/knowledgecode/jquery-param/blob/master/jquery- param.js Cela a très bien fonctionné pour moi!

    var param = function (a) {
    var s = [], rbracket = /\[\]$/,
        isArray = function (obj) {
            return Object.prototype.toString.call(obj) === '[object Array]';
        }, add = function (k, v) {
            v = typeof v === 'function' ? v() : v === null ? '' : v === undefined ? '' : v;
            s[s.length] = encodeURIComponent(k) + '=' + encodeURIComponent(v);
        }, buildParams = function (prefix, obj) {
            var i, len, key;

            if (prefix) {
                if (isArray(obj)) {
                    for (i = 0, len = obj.length; i < len; i++) {
                        if (rbracket.test(prefix)) {
                            add(prefix, obj[i]);
                        } else {
                            buildParams(prefix + '[' + (typeof obj[i] === 'object' ? i : '') + ']', obj[i]);
                        }
                    }
                } else if (obj && String(obj) === '[object Object]') {
                    for (key in obj) {
                        buildParams(prefix + '[' + key + ']', obj[key]);
                    }
                } else {
                    add(prefix, obj);
                }
            } else if (isArray(obj)) {
                for (i = 0, len = obj.length; i < len; i++) {
                    add(obj[i].name, obj[i].value);
                }
            } else {
                for (key in obj) {
                    buildParams(key, obj[key]);
                }
            }
            return s;
        };

    return buildParams('', a).join('&').replace(/%20/g, '+');
};
2
Vandana Sharma

C’est une solution qui fonctionnera immédiatement avec les systèmes .NET. J'ai pris la réponse principale de ce fil de discussion et l'ai mise à jour pour répondre à nos besoins .NET.

function objectToQuerystring(params) {
var result = '';

    function convertJsonToQueryString(data, progress, name) {
        name = name || '';
        progress = progress || '';
        if (typeof data === 'object') {
            Object.keys(data).forEach(function (key) {
                var value = data[key];
                if (name == '') {
                    convertJsonToQueryString(value, progress, key);
                } else {
                    if (isNaN(parseInt(key))) {
                        convertJsonToQueryString(value, progress, name + '.' + key);
                    } else {
                        convertJsonToQueryString(value, progress, name + '[' + key+ ']');
                    }
                }
            })
        } else {
            result = result ? result.concat('&') : result.concat('?');
            result = result.concat(`${name}=${data}`);
        }
    }

    convertJsonToQueryString(params);
    return result;
}
2
Angel Venchev

ok, c’est un article plus ancien, mais je suis confronté à ce problème et j’ai trouvé ma solution personnelle. Peut-être que je pourrais aider quelqu'un d’autre ..

     function objToQueryString(obj){
        var k = Object.keys(obj);
        var s = "";
        for(var i=0;i<k.length;i++) {
            s += k[i] + "=" + encodeURIComponent(obj[k[i]]);
            if (i != k.length -1) s += "&";
        }
        return s;
     };
2
hayatoShingu

SOLUTION ES6 POUR LE CODAGE D'UN OBJET JAVASCRIPT PAR CHAÎNES DE CHAÎNES

const params = {
  a: 1,
  b: 'query stringify',
  c: null,
  d: undefined,
  f: '',
  g: { foo: 1, bar: 2 },
  h: ['Winterfell', 'Westeros', 'Braavos'],
  i: { first: { second: { third: 3 }}}
}

static toQueryString(params = {}, prefix) {
  const query = Object.keys(params).map((k) => {
    let key = k;
    const value = params[key];

    if (!value && (value === null || value === undefined || isNaN(value))) {
      value = '';
    }

    switch (params.constructor) {
      case Array:
        key = `${prefix}[]`;
        break;
      case Object:
        key = (prefix ? `${prefix}[${key}]` : key);
        break;
    }

    if (typeof value === 'object') {
      return this.toQueryString(value, key); // for nested objects
    }

    return `${key}=${encodeURIComponent(value)}`;
  });

  return query.join('&');
}

toQueryString (params)

"a=1&b=query%20stringify&c=&d=&f=&g[foo]=1&g[bar]=2&h[]=Winterfell&h[]=Westeros&h[]=Braavos&i[first][second][third]=3"
1
gandharv garg

Vous pouvez également y parvenir en utilisant simple JavaScript .

const stringData = '?name=Nikhil&surname=Mahirrao&age=30';
    
const newData= {};
stringData.replace('?', '').split('&').map((value) => {
  const temp = value.split('=');
  newData[temp[0]] = temp[1];
});

console.log('stringData: '+stringData);
console.log('newData: ');
console.log(newData);

0
Nikhil Mahirrao

Il suffit d'utiliser ce qui suit:

encodeURIComponent(JSON.stringify(obj))

// elastic search example
let story ={
  "query": {
    "bool": {
      "must": [
        {
          "term": { 
            "revision.published": 0, 
          }
        },
        {
          "term": { 
            "credits.properties.by.properties.name": "Michael Guild"
          }
        },
        {
          "nested": {
            "path": "taxonomy.sections",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "taxonomy.sections._id": "/science"
                    }
                  },
                  {
                    "term": {
                      "taxonomy.sections._website": "staging"
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}


const whateva = encodeURIComponent(JSON.stringify(story))
console.log(whateva)

0
Michael Guild

Référez-vous à partir de la réponse @ utilisateur187291, ajoutez "isArray" en tant que paramètre pour convertir le tableau imbriqué json.

data : {
                    staffId : "00000001",
                    Detail : [ {
                        "identityId" : "123456"
                    }, {
                        "identityId" : "654321"
                    } ],

                }

Pour faire le résultat: 

staffId = 00000001 & Detail [0] .identityId = 123456 & Detail [1] .identityId = 654321

serialize = function(obj, prefix, isArray) {
        var str = [],p = 0;
        for (p in obj) {
            if (obj.hasOwnProperty(p)) {
                var k, v;
                if (isArray)
                    k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
                else
                    k = prefix ? prefix + "." + p + "" : p, v = obj[p];

                if (v !== null && typeof v === "object") {
                    if (Array.isArray(v)) {
                        serialize(v, k, true);
                    } else {
                        serialize(v, k, false);
                    }
                } else {
                    var query = k + "=" + v;
                    str.Push(query);
                }
            }
        }
        return str.join("&");
    };

    serialize(data, "prefix", false);
0
Long Ranger

Voici une réponse simple qui traite à la fois des chaînes et des tableaux lors de la conversion.

jsonToQueryString: function (data) {
        return Object.keys(data).map((key) => {
            if (Array.isArray(data[key])) {
                return (`${encodeURIComponent(key)}=${data[key].map((item) => encodeURIComponent(item)).join('%2C')}`);
            }
            return(`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`);
        }).join('&');
    }
0
Remario

Juste une autre manière (pas d'objet récursif):

   getQueryString = function(obj)
   {
      result = "";

      for(param in obj)
         result += ( encodeURIComponent(param) + '=' + encodeURIComponent(obj[param]) + '&' );

      if(result) //it's not empty string when at least one key/value pair was added. In such case we need to remove the last '&' char
         result = result.substr(0, result.length - 1); //If length is zero or negative, substr returns an empty string [ref. http://msdn.Microsoft.com/en-us/library/0esxc5wy(v=VS.85).aspx]

      return result;
   }

alert( getQueryString({foo: "hi there", bar: 123, quux: 2 }) );
0
Marco Demaio

const buildSortedQuery = (args) => {
    return Object.keys(args)
        .sort()
        .map(key => {
            return window.encodeURIComponent(key)
                + '='
                + window.encodeURIComponent(args[key]);
        })
        .join('&');
};

console.log(buildSortedQuery({
  foo: "hi there",
  bar: "100%"
}));

//bar=100%25&foo=hi%20there

0
Anthony Zhan
const serialize = obj => Object.keys(obj).reduce((a, b) =>
    a.Push(encodeURIComponent(b) + "=" + encodeURIComponent(obj[b])) && a,
    []).join("&");

Appel:

console.log(serialize({a:1,b:2}));
// output: 'a=1&b=2

'

0
Behnam Mohammadi
const querystring=  {};

querystring.stringify = function (obj, sep = '&', eq = '=') {
  const escape = encodeURIComponent;
  const qs = [];
  let key = null;

  for (key in obj) if (obj.hasOwnProperty(key)) {
    qs.Push(escape(key) + eq + escape(String(obj[key])));
  }
  return qs.join(sep);
};

Exemple:

const a  = querystring.stringify({a: 'all of them', b: true});
console.log(a);  // Output: a=all%20of%20them&b=true
0
silver daymon