是否有通过查询字符串传递数组的标准方法?
明确起见,我有一个具有多个值的查询字符串,其中一个值将是数组值。我希望查询字符串值被视为数组-我不希望数组被分解,以便它与其他查询字符串变量难以区分。
另外,根据这篇文章的回答,作者建议不定义对数组的查询字符串支持。这准确吗?
编辑:
基于@Alex的回答,没有标准的方法来做到这一点,所以我的后续是什么是一个简单的方法来识别我正在阅读的参数是一个数组在PHP和Javascript?
将多个参数命名为相同的名称是否可以接受,这样我就知道它们属于一个数组?例子:
?myarray=value1&myarray=value2&myarray=value3...
或者这是一种不好的做法?
我不认为有一个标准。
每个网络环境都为这些事情提供了自己的“标准”。此外,url通常太短(在某些浏览器上限制为256字节)。当然,更长的数组/数据可以通过POST请求发送。
但是,有一些方法:
There's a PHP way, which uses square brackets ([,]) in URL queries. For example a query such as ?array_name[]=item&array_name[]=item_2 has been said to work, despite being poorly documented, with PHP automatically converting it into an array. Source: https://stackoverflow.com/a/9547490/3787376
Object data-interchange formats (e.g. JSON - official website, PHP documentation) can also be used if they have methods of converting variables to and from strings as JSON does.
Also an url-encoder (available for most programming languages) is required for HTTP get requests to encode the string data correctly.
尽管“方括号方法”简单且有效,但它仅限于PHP和数组。
如果需要其他类型的变量,如类或在非PHP语言的查询字符串中传递变量,则建议使用JSON方法。
PHP中的JSON方法示例(方法2):
$myarray = array(2, 46, 34, "dfg");
$serialized = json_encode($myarray)
$data = 'myarray=' . rawurlencode($serialized);
// Send to page via cURL, header() or other service.
接收页面代码(PHP):
$myarray = json_decode($_GET["myarray"]); // Or $_POST["myarray"] if a post request.
你可以使用这些函数,但要确保不要在对象键上使用“-”。
// convert obj to url params
function objToUrlParams(obj) {
let toUrlParams = (obj, prefex = '') => {
// create url params
let urlParams = "";
// loop through obj
for (let key in obj) {
let val = obj[key];
if (val == null) continue;
if (val == undefined) continue;
// if(val == '') continue;
// if val is an object then call toUrlParams
if (val instanceof Array) {
// convert val from Array to object
let valToObj = {};
val.forEach((v, i) => {
valToObj[i] = v;
});
val = valToObj;
}
let newPrefex = prefex + key;
if (val instanceof Object) {
urlParams += toUrlParams(val, newPrefex + '-');
} else {
urlParams += newPrefex + '=' + val;
}
urlParams += '&';
}
// remove last &
urlParams = urlParams.slice(0, -1);
// return url params
return urlParams;
}
// encodeURI
return encodeURI(toUrlParams(obj));
}
// convert url params to obj
function urlParamsToObj(urlParams) {
// decodeURI
urlParams = decodeURI(urlParams);
let toObj = (urlParams) => {
let obj = {};
let urlParamsArr = urlParams.split('&');
let subUrlParramsObj = {};
// loop through urlParams
for (let i = 0; i < urlParamsArr.length; i++) {
let item = urlParamsArr[i];
// get key and value
let key = item.split('=')[0];
let val = item.split('=')[1] ?? null;
let keys = key.split('-');
if (val == "null") {
val = null;
} else if (val == "undefined") {
val = undefined;
} else if (val == "true") {
val = true;
} else if (val == "false") {
val = false;
} else if (val == "NaN") {
val = NaN;
} else if (val == "Infinity") {
val = Infinity;
}
// if keys length is 1 then set obj[key] to val
if (keys.length == 1) {
// check if obj contains key
if (obj.hasOwnProperty(key)) {
// if obj[key] is an array then push val
if (obj[key] instanceof Array) {
obj[key].push(val);
} else {
// create array and push val
obj[key] = [obj[key], val];
}
} else {
obj[key] = val;
}
}
// if keys length is 2 then set obj[keys[0]][keys[1]] to val
else if (keys.length > 1) {
let key0 = keys[0];
// check if subUrlParramsObj contains keys[0]
if (!subUrlParramsObj[key0]) {
subUrlParramsObj[key0] = [];
}
// remove keys[0] from keys
keys.shift();
// join keys with -
key = keys.join('-');
let param = key + '=' + val;
// add param to subUrlParramsObj[keys[0]]
subUrlParramsObj[key0].push(param);
}
}
// loop through subUrlParramsObj
for (let key in subUrlParramsObj) {
// join subUrlParramsObj[key] with &
let val = subUrlParramsObj[key].join('&');
// set obj[key] to val
obj[key] = toObj(val);
}
// return obj
return obj;
}
return checkIfObjShouldBeArrayAndConvert(toObj(urlParams));
}
// check if object should be converted to array, if its keys are numbers
function checkIfObjShouldBeArrayAndConvert(obj) {
// if obj is an array
if (obj instanceof Array) {
// loop through obj
obj.forEach((item, i) => {
// check if item is an object
if (item instanceof Object) {
// convert item to array
obj[i] = checkIfObjShouldBeArrayAndConvert(item);
}
});
// return obj
return obj;
}
// check if all keys are numbers
let canConvertToArray = true;
for (let key in obj) {
// get value
let val = obj[key];
// check if value is an object or Array
if (val instanceof Object || val instanceof Array) {
obj[key] = checkIfObjShouldBeArrayAndConvert(val);
}
if (isNaN(key)) {
canConvertToArray = false;
}
}
// order obj by keys
let orderedObj = {};
Object.keys(obj).sort().forEach(function(key) {
orderedObj[key] = obj[key];
});
// check if the first key is 0
if (Object.keys(orderedObj)[0] != 0) {
canConvertToArray = false;
}
// check if the keys step is 1
let keys = Object.keys(orderedObj);
// loop through keys
for (let i = 0; i < keys.length - 1; i++) {
// get key
let key = keys[i];
// get next key
let nextKey = keys[i + 1];
// get key step
let keyStep = nextKey - key;
// check if key step is 1
if (keyStep != 1) {
canConvertToArray = false;
break;
}
}
// if all keys are numbers then convert obj to array
if (canConvertToArray) {
let arr = [];
for (let key in orderedObj) {
arr.push(orderedObj[key]);
}
return arr;
}
// return obj
return obj;
}
// add params to url
function addParamsToUrl(params, url = window.location.href) {
// check if url has params
if (url.indexOf('?') == -1) {
url += '?';
} else {
url += '&';
}
return url + params ?? '';
}
function addObjToUrl(obj, url = window.location.href) {
return addParamsToUrl(objToUrlParams(obj), url);
}
// extract params from url
function extractParamsFromUrl(url = window.location.href) {
return urlParamsToObj(url.split('?')[1]);
}
// test
let urlParams = objToUrlParams({
a: 1,
b: "zad",
c: {
d: 2,
e: "f"
},
j: [1, 2, 3, 4]
});
console.log(urlParams); // a=1&b=zad&c-d=2&c-e=f&j=1&j=2&j=3&j=4
let obj = urlParamsToObj(urlParams);
console.log(obj); // { "a": "1", "b": "zad", "j": [ "1", "2", "3", "4" ], "c": { "d": "2", "e": "f" } }
虽然URL部分没有标准,但JavaScript或多或少有一个标准。
数组。方法返回以逗号分隔的项目字符串。
因此,如果你将包含数组的对象传递给URLSearchParams,并对其调用toString(),它将反过来对每个值调用toString,结果如下所示:
let data = {
name: 'abc',
values: ['abc', 123]
}
new URLSearchParams(data).toString();
// ?name=abc&values=abc,123 (with escaped comma characters)
这种格式很容易在前端序列化,也很容易在任何服务器上解析,而且无论上下文如何都很容易理解,所以它往往是我在url中发送数组数据的首选。