How can I get complex URI query string parameters

2019-08-31 11:04发布

My question is about full power solution for parsing ANY complex URI parameters using just normal browser's Javascript. Like it do PHP, for simple code compatibility between JS and PHP sources.

But the first, let us see some particular known decisions:


1. There is popular question and answers on StackOverflow, see How can I get query string values in JavaScript?

You can find there quite simple solutions for common SIMPLE cases. For example, like handling this scalar parameters like this one:

https://example.com/?name=Jonathan&age=18

It has no answers for handling complex query params. (As far as I could see for answers with source codes and author comments)


2. Also you may use an URL object in modern browsers, see https://developer.mozilla.org/en-US/docs/Web/API/URL, or exactly https://developer.mozilla.org/en-US/docs/Web/API/URL/searchParams

It is enought powerful and you don't need to write or load any code for parsing URI parameters - just use

var params = (new URL(document.location)).searchParams;
var name = params.get("name"); // is the string "Jonathan"
var age = parseInt(params.get("age")); // is the number 18

This approach has such disadvantage that URL is available only in most of modern browsers, - other browsers or outdated versions of browsers will fail.


So, what I need. I need parsing any complex URI params, like

https://example.com/?a=edit&u[name]=Jonathan&u[age]=18&area[]=1&area[]=20&u[own][]=car&u[own][]=bike&u[funname]=O%27Neel%20mc%20Fly&empty=&nulparam&the%20message=Hello%20World

to

{
    'a': 'edit',
    'u': {
        'name': 'Jonathan',
        'age': '18',
        'own': ['car', 'bike'],
        'funname': 'O\'Neel mc Fly'
    },
    'area': [1, 20],
    'empty': '',
    'nulparam': null,
    'the message': 'Hello World'
}

Preferrable answer is just plain readable javascript source. Simple and small wide-used library can be accepted too, but this question is not about them.

`

PS: To start I just publish my own current solution for parsing URI params and vice versa for making URI from params. Any comments for it are welcome.

Hope this helps to save time for lot of coders later.

2条回答
放荡不羁爱自由
2楼-- · 2019-08-31 11:46

A bit late, but just struggled over the same problem, solution was very simple:

use encodeURIComponent(...) for the stringified complex objects, the result can then be used as normal queryString-Part.

In the result-side the query-string-parameters have to be un-stringified.

Example:

var complex_param_obj = {
value1: 'Wert1',
value2:4711
};
console.log(restored_param_obj);

var complex_param_str = encodeURIComponent(JSON.stringify(complex_param_obj));
console.log(complex_param_str);
var complex_param_url = 'http://test_page.html?complex_param=' + complex_param_str;

//on the result-side you would use something to extract the complex_param-attribute from the URL
//in this test-case:

var restored_param_obj = decodeURIComponent(complex_param_str);
console.log(restored_param_obj);
查看更多
Ridiculous、
3楼-- · 2019-08-31 11:53

My solution

Usage:

var params = getQueryParams(location.search);
var params = getQueryParams();

var params = {...};
var path = '...';
var url = path;
var urlSearch = getQueryString(params);
if (urlSearch) {
    url += '?' + urlSearch;
}
history.replaceState({"autoUrl": url}, "autoreplace", url);

Code:

function getQueryParams(qs) {
  if (typeof qs === 'undefined') {
    qs = location.search;
  }

  qs = qs.replace(/\+/g, ' ');

  var params = {},
      tokens,
      re = /[?&]?([^=]+)=([^&]*)/g;

  while (tokens = re.exec(qs)) {
    var name = decodeURIComponent(tokens[1]);
    var value = decodeURIComponent(tokens[2]);
    if (value.length == 0) {
      continue;
    }

    if (name.substr(-2) == '[]') {
      name = name.substr(0, name.length - 2);
      if (typeof params[name] === 'undefined') {
        params[name] = [];
      }
      if (value === '') {
        continue;
      }
      params[name].push(value);
      continue;
    }

    if (name.substr(-1) == ']') {
      var nameParts = name.split('[');
      name = nameParts[0];
      for (var i = 1; i < nameParts.length; i++) {
        nameParts[i] = nameParts[i].substr(0, nameParts[i].length - 1);
      }
      var ptr = params;
      for (var i = 0; i < nameParts.length - 1; i++) {
        name = nameParts[i];
        if (typeof ptr[name] === 'undefined') {
          ptr[name] = {};
        }
        ptr = ptr[name];
      }
      name = nameParts[nameParts.length - 1];
      ptr[name] = value;
      continue;
    }

    params[name] = value;
  }

  return params;
}

function getQueryString(params) {
  var paramsStringParts = [];

  for (var name in params) {
    if (params[name] instanceof Array) {
      paramsStringParts.push( name + '[]=' + params[name].join('&' + name + '[]=') );
    } else if (typeof params[name] === 'object') {

      var makeFlattern = function(obj){
        var result = [];

        if (obj instanceof Array) {
          for (var i = 0; i < obj.length; i++) {
            result.push('[]=' + obj[i]);
          }
          return result;
        }

        for (var i in obj) {
          if (typeof obj[i] === 'object') {
            var subResult = makeFlattern(obj[i]);
            for (var j = 0; j < subResult.length; j++) {
              result.push('[' + i + ']' + subResult[j]);
            }
            continue;
          }
          result.push('[' + i + ']=' + obj[i]);
        }
        return result;
      };

      paramsStringParts.push( name + makeFlattern(params[name]).join('&' + name) );
    } else {
      paramsStringParts.push( name + '=' + params[name] );
    }
  }

  return paramsStringParts.join('&');
}
查看更多
登录 后发表回答