如何在查询字符串中传递数组?

是否有通过查询字符串传递数组的标准方法?

明确起见,我有一个具有多个值的查询字符串,其中一个值将是数组值。我希望查询字符串值被视为数组-我不希望数组被分解,以便它与其他查询字符串变量难以区分。

此外,根据这个后的答案,作者建议不定义对数组的查询字符串支持。这准确吗?

编辑:

基于@Alex的回答,没有标准的方法来做到这一点,所以我的后续是什么是识别的简单方法,我正在读取的参数是一个数组在PHPJavascript?

将多个参数命名为相同的名称是否可以接受,这样我就知道它们属于一个数组?例子:

?myarray=value1&myarray=value2&myarray=value3...

或者这是一种不好的做法?

902053 次浏览

查询字符串携带文本数据,所以没有选择,只能分解数组,正确编码,并以您选择的表示格式传递:

< p > # EYZ0 < br > # EYZ0 < br > # EYZ0 < / p >

然后在服务器端代码中解码。

我认为没有一个标准 每个网络环境都为这些事情提供了自己的“标准”。此外,url通常太短(在某些浏览器上限制为256字节)。当然,更长的数组/数据可以通过POST请求发送

但是,有一些方法:

  1. 有一种PHP方法,在URL查询中使用方括号([])。例如,有人说?array_name[]=item&array_name[]=item_2这样的查询是可以工作的,尽管没有很好的文档说明,PHP会自动将其转换为数组。来源:https://stackoverflow.com/a/9547490/3787376

  2. 对象数据交换格式(例如JSON - 官方网站PHP文档)也可以使用,如果它们像JSON一样有方法将变量转换为字符串 HTTP get请求还需要一个url编码器(适用于大多数编程语言)来正确编码字符串数据
虽然“方括号方法”简单且有效,但它仅限于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.

您可以使用http_build_query从PHP中的数组生成url编码的查询字符串。虽然结果的查询字符串将被展开,但您可以决定一个惟一的分隔符作为http_build_query方法的参数,因此在解码时,您可以检查使用了什么分隔符。如果它是你选择的唯一的一个,那么它将是数组querystring,否则它将是普通的querystring。

以下是我的结论:

提交多值表单字段,即通过GET/POST变量提交数组,可以通过几种不同的方式完成,因为没有必要详细说明标准。

发送多值字段或数组的三种可能的方法是:

  • # EYZ0 # EYZ1
  • # EYZ0 # EYZ1
  • # EYZ0 # EYZ1

形式的例子

在表单中,多值字段可以采用选择框设置为多个的形式:

<form>
<select multiple="multiple" name="cars[]">
<option>Volvo</option>
<option>Saab</option>
<option>Mercedes</option>
</select>
</form>

# EYZ1

... 或多个具有相同名称的隐藏字段:

<input type="hidden" name="cars[]" value="Volvo">
<input type="hidden" name="cars[]" value="Saab">
<input type="hidden" name="cars[]" value="Mercedes">

对于多个值使用field[]的记录非常少。在查询字符串- Wikipedia中关于多值键的部分,或者在W3C文档中处理多选输入的部分,我没有看到任何提到它。


更新

正如评论者所指出的,这是非常特定于框架的。一些例子:

查询字符串:

?list_a=1&list_a=2&list_a=3&list_b[]=1&list_b[]=2&list_b[]=3&list_c=1,2,3

Rails:

"list_a": "3",
"list_b":[
"1",
"2",
"3"
],
"list_c": "1,2,3"

角:

 "list_a": [
"1",
"2",
"3"
],
"list_b[]": [
"1",
"2",
"3"
],
"list_c": "1,2,3"

(角# EYZ0)

参见node . jsWordpressASP.net中的示例注释


< >强维持秩序: 还有一件需要考虑的事情是,如果你需要维护你的项目的订单(即数组作为一个有序列表),你实际上只有一个选择,这就是传递一个分隔值列表,并显式地将其转换为一个数组

检查parse_string函数http://php.net/manual/en/function.parse-str.php

它将返回查询字符串中的所有变量,包括数组。

来自php.net的例子:

<?php
$str = "first=value&arr[]=foo+bar&arr[]=baz";
parse_str($str);
echo $first;  // value
echo $arr[0]; // foo bar
echo $arr[1]; // baz


parse_str($str, $output);
echo $output['first'];  // value
echo $output['arr'][0]; // foo bar
echo $output['arr'][1]; // baz


?>

我觉得这对于正在寻找将查询字符串中的数组传递给servlet的人是有帮助的。我测试了下面的查询字符串,并能够使用req.getgetParameterValues()获得数组值;方法。下面是我通过浏览器传递的查询字符串。

  http://localhost:8080/ServletsTutorials/*.html?
myname=abc&initial=xyz&checkbox=a&checkbox=b

复选框是这里的参数数组。

你在问题中提到了PHP和Javascript,但没有在标签中提到。我提出这个问题的目的是将一个数组传递给MVC。网行动。

我找到了我的问题在这里的答案:预期的格式是你在问题中提出的格式,多个参数具有相同的名称。

这对我来说很管用:

在link中,to属性具有值:

to="/filter/arr?fruits=apple&fruits=banana"

Route可以处理这个:

path="/filter/:arr"

对于多个数组:

to="filter/arr?fruits=apple&fruits=banana&vegetables=potato&vegetables=onion"

路线不变。

截图

enter image description here

< >强更新: 为了实现这个字符串结构,查询字符串是最好的包

例如:

import { stringify, parse } from 'query-string';


const queryParams={
fruits:['apple','banana'],
vegetables:['potato','onion']
}
//arrayFormat can be bracket or comma
stringify(queryParams, { arrayFormat: 'bracket' });

我使用React和Rails。我做了:

js

  let params = {
filter_array: ['A', 'B', 'C']
}


...


//transform params in URI


Object.keys(params).map(key => {
if (Array.isArray(params[key])) {
return params[key].map((value) => `${key}[]=${value}`).join('&')
}
}
//filter_array[]=A&filter_array[]=B&filter_array[]=C

虽然URL部分没有标准,但JavaScript或多或少有一个标准。

Array.toString方法返回以逗号分隔的项目字符串。

因此,如果你将包含数组的对象传递给URLSearchParams,并对其调用toString(),它将依次对每个值调用toString,结果如下所示:

let data = {
name: 'abc',
values: ['abc', 123]
}


new URLSearchParams(data).toString();
// ?name=abc&values=abc,123 (with escaped comma characters)

这种格式很容易在前端序列化,也很容易在任何服务器上解析,而且无论上下文如何都很容易理解,所以它往往是我在url中发送数组数据的首选。

注意,query-string模块列出了它支持的不同类型的数组编码(https://www.npmjs.com/package/query-string):

例如,{foo:['1', '2', '3']}可以被编码为:

'foo[]=1&foo[]=2&foo[]=3'
'foo[0]=1&foo[1]=2&foo[3]=3'
'foo=1,2,3'
'foo=1&foo=2&foo=3'
// Any custom separator can be used:
'foo=1|2|3'
// ... and more custom formats

这表明有很多解决方案被采用了……

你可以使用这些函数,但要确保不要在对象键上使用“-”。

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