在GET请求中传递相同参数名称的多个值的正确方式

327

我正在研究在GET请求中传递同一参数名称的多个值的正确方式。

我看到过这样的URL:

http://server/action?id=a&id=b

我见过这样的URL:

http://server/action?id=a,b

我的理解是第一种方式正确,但我找不到任何相关的参考资料。我查阅了HTTP规范,但没有找到有关URL“查询”部分应该如何组成的内容。

我不希望得到一个回答说“两种都可以”,如果我正在构建一个Web服务,我想知道哪种方法是标准的,这样使用我的Web服务的人就知道如何传递相同名称的多个参数。

所以,有人能指向官方参考来源以确认哪个选项是正确的吗?

7个回答

256

事实上,没有明确定义的标准。要支持这一信息,请查看维基百科中的查询字符串章节。以下是相关评论:

虽然没有明确的标准,但大多数Web框架允许将多个值与单个字段相关联。[3][4]

此外,当您查看RFC 3986中的第3.4节 查询(Query)时,没有定义具有多个值的参数。

大多数应用程序使用您展示的第一个选项:http://server/action?id=a&id=b。要支持该信息,请查看此Stackoverflow链接和关于ASP.NET应用程序使用相同标准的此MSDN链接

然而,由于您正在开发API,我建议您选择最简单的方法,因为调用API的人不会在创建查询字符串时遇到太多麻烦。


如果没有任何相反的信息,我猜你是对的 - 如果RFC3986没有指定标准,那就没有标准。谢谢Eduardo。 - stripybadger
46
建议使用 id=a&id=b 表示逻辑与(AND),使用 id=a,b 表示逻辑或(OR)。请注意,在这里的逗号表示“或”的含义。 - Alex Skrypnyk
22
PHP不支持读取像?id=5&id=3这样的参数。在这种情况下,PHP只会读取一个id值。如果我没记错的话,要想使其与PHP一起使用,必须将它写成这样:?id[]=5&id[]=3 - What have you tried
4
+1意味着“同意”。“since you are developing the APIs, I suggest you to do what is the easiest for you, since the caller of the API will not have much trouble creating the query string.”可以翻译为“既然你正在开发API,我建议你做对你来说最容易的事情,因为调用API的人创建查询字符串不会有太多麻烦。” - Amr
13
id=a,b 假设逗号 , 是一个有效的分隔符。但是你的参数值可能包含逗号 ,。那么客户端需要转义查询参数值中的逗号 ,。但你也可以决定使用分号 ; 更好。这意味着客户端和服务器应该共享 API 的正式分隔符。id=a&id=b 尽管会使 URL 更长,但不会有这个问题。 - Ronan Quillevere
显示剩余4条评论

23

我建议查看浏览器如何默认处理表单。例如,看一下form元素<select multiple>以及它如何处理来自w3schools上这个例子的多个值。

<form action="/action_page.php">
<select name="cars" multiple>
  <option value="volvo">Volvo</option>
  <option value="saab">Saab</option>
  <option value="opel">Opel</option>
  <option value="audi">Audi</option>
</select>
<input type="submit">
</form>

对于 PHP 使用:

<select name="cars[]" multiple>

w3schools.com上的实时示例

如果您从上面选择了"saab, opel"并点击提交,它将生成一个cars=saab&cars=opel结果。然后根据后端服务器,参数cars应该转换为数组,您可以进一步处理。

希望这能帮助任何寻找更加“标准”处理此问题的人。


14

我在描述一个在Python(Django框架)中非常顺畅的简单方法。

1. 发送请求时,请像这样发送请求

http://server/action?id=a,b

2. 现在在我的后端,我使用split函数来拆分接收到的值,该函数总是创建一个列表。

id_filter = id.split(',')

例子: 那么如果我在请求中发送了两个值,

http://server/action?id=a,b

那么数据的过滤器就是

id_filter = ['a', 'b']
如果我在请求中只发送一个值,
http://server/action?id=a

那么过滤器的结果就是

id_filter = ['a']

3. 真正过滤数据时,我只需使用“in”函数

queryset = queryset.filter(model_id__in=id_filter)

大致上执行与SQL等价的操作

WHERE model_id IN ('a', 'b')

在第一次请求时,

WHERE model_id IN ('a')

使用第二个请求。

如果请求中有超过2个参数值,这也可以工作!


2
如果值本身带有逗号怎么办?比如我可能有两个值: "abc" "p,q" - Vipul Agarwal
1
@VipulAgarwal 我会建议使用以下任一方法,a) 转义逗号。b) 使用逗号的 ASCI 编码。c) 使用其他字符,如;|¦¬等。d) 在 API 文档中声明该查询参数不能使用逗号。实际上有很多种处理这种情况的方法,这和声明要在查询参数中使用“&”没有什么区别。所有相同的解决方法都适用于使用逗号。 - Jack_Hu

4

我的答案更加偏向于PHP

提交多值表单字段,例如提交数组,有几种不同的方法可以实现,因为并没有明确的标准。

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

  • ?cars[]=Saab&cars[]=Audi(最佳方式- PHP将其读入数组中)
  • ?cars=Saab&cars=Audi(不好的方式- PHP只会记录最后一个值)
  • ?cars=Saab,Audi(通用方式- 需要将字符串分割以获取值作为数组)

例如:

http://localhost:3000/foo?id[]=a&id[]=b

返回

Array
(
  [id] => Array
     (
       [0] => a
       [1] => b
     )
)

(注意:在这种情况下,重要的是将查询关键字命名为some_name[],以便PHP将生成的请求变量注册为数组)

3
上述解决方案无效。它只显示了最后一组键/值对,但以下内容有效:
http://localhost/?key[]=1&key[]=2
返回:
Array
(
[key] => Array
    (
        [0] => 1
        [1] => 2
    )

2

目前没有标准,但大多数框架都支持两种方式。例如,Java Spring 可以接受 这里

@GetMapping("/api/foos")
@ResponseBody
public String getFoos(@RequestParam List<String> id) {
    return "IDs are " + id;
}

Spring MVC 将映射逗号分隔的 id 参数:

http://localhost:8080/api/foos?id=1,2,3
----
IDs are [1,2,3]

或者是单独的id参数列表:

http://localhost:8080/api/foos?id=1&id=2
----
IDs are [1,2]

1
请不要只发布纯网址。它们可能在未来失效。 - mate00

0

由于URL是单参数和多个值,Java中非常简单的解决方案是将字符串拆分,然后将其附加到自身。例如下面:

String baseUrl = "http://server/action"
String id = "a,b";
StringBuilder url = new StringBuilder();
url = baseUrl.append("?");
String[] idArr = id.split(",");
StringBuilder sb = new StringBuilder();
for ( String fetchId : idArr) {
        sb.append("&id=").append(fetchId);
        url.append(sb);
}

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