重复的HTTP GET查询键的权威位置


137

我在查找有关HTTP GET查询字符串重复字段的行为的权威信息时遇到麻烦,例如

http://example.com/page?field=foo&field=bar 

尤其是是否保留订单。大多数面向Web的语言都会生成一个包含与键“字段”相关联的foo和bar的数组,但是我想知道关于这一点是否存在权威性声明(例如,在RFC上)。RFC 3986有一个section 3.4. Query,它引用键=值对,但是没有任何关于如何解释顺序和重复字段等的说明。这是有道理的,因为它是后端相关的,不在RFC的范围内...

尽管存在事实上的标准,但出于好奇,我希望看到它的权威来源。


也想知道这一点。另一件事是关于将查询字符串中的参数与POST正文中的参数合并的规范。
Thilo

在代码牧场,人们说没有订单保证。但是该线程很旧,没有人以任何方式对其进行备份:coderanch.com/t/357197/Servlets/java/getParameterValues-order
Thilo

1
除了服务器保持查询字符串的顺序外,还存在有关浏览器以DOM(或其他固定方式)发送查询字符串的问题。
Thilo

Answers:


112

目前没有规范这一点。你可以做你喜欢的事。

典型的方法包括:首先给出,最后给出,所有数组,所有字符串以逗号分隔。

假设原始请求是:

GET /blog/posts?tag=ruby&tag=rails HTTP/1.1
Host: example.com

然后request.query['tag'],根据语言或框架,有各种选项可以产生什么结果:

request.query['tag'] => 'ruby'
request.query['tag'] => 'rails'
request.query['tag'] => ['ruby', 'rails']
request.query['tag'] => 'ruby,rails'

12
更重要的是,还可以选择['rails','ruby'](不同顺序)。
Thilo

2
当然可以做很多事情。
yfeldblum

6
.NET将为您提供一个数组(测试时我并不关心顺序),PHP将始终为您提供最后一个值,而Java(至少是我基于Java使用的系统)始终是您的第一个值。stackoverflow.com/questions/1809494/...
SimonSimCity

17
这是基于一种称为HTTP参数污染的攻击,并且已经由OWASP进行了分析:owasp.org/images/b/ba/AppsecEU09_CarettoniDiPaola_v0.8.pdf在第9页上,您将找到20个系统的列表以及它们如何处理的描述。这个问题。
SimonSimCity 2012年

1
除此之外,@ SimonSimCity,如果您在方括号后附加带有可选索引的参数名称,PHP实际上会创建一个数组。
Martin Ender 2013年

14

我可以确认对于PHP(至少在4.4.4版和更高版本中),它的工作方式如下:

GET /blog/posts?tag=ruby&tag=rails HTTP/1.1
Host: example.com

结果是:

request.query['tag'] => 'rails'

GET /blog/posts?tag[]=ruby&tag[]=rails HTTP/1.1
Host: example.com

结果是:

request.query['tag'] => ['ruby', 'rails']

对于GET和POST数据,此行为相同。


1
[]后缀看起来很奇怪的行为,但如果你尝试发送一个数组作为通过jQuery的一个参数.ajax(),那么它会自动以同样的方式添加它们。看来这对PHP用户有利。
伊恩·克拉克

4
@IanClark对PHP编码人员来说很直观-在纯PHP中,$foo[] = 1追加到数组。Django(Python)也做同样的事情。
Izkata

可以在Apache Tomcat上验证它是否返回逗号连接的字符串。
Gaurav Ojha,

8

yfeldblum的答案很完美。

只是关于我最近注意到的第五种行为的注释:在Windows Phone上,使用带有重复查询键的uri打开应用程序将导致NavigationFailed出现:

System.ArgumentException:已添加具有相同键的项。

罪魁祸首是System.Windows.Navigation.UriParsingHelper.InternalUriParseQueryStringToDictionary(Uri uri, Boolean decodeResults)

因此,该系统甚至无法让您按自己的方式处理它,它将禁止它。您剩下的唯一解决方案是选择自己的格式(CSV,JSON,XML等)和uri-escape-it。


2
这似乎是该功能的内部错误,而不是设计选择。可能的功能不在创建的字典中检查重复的键。当然,字典需要唯一的键。
gligoran

1
因此,在这种情况下,客户端浏览器(而非服务器)正在引发错误?它似乎确实是一个错误。我想知道今天是否仍然存在此错误?
乔恩·施耐德

1
@JonSchneider是的,客户端正在抛出NavigationFailed此类URI。但是,请原谅,在这篇文章发表后的一个月,我放弃了Windows(Phone)开发,而转而使用了macOS(iOS),所以现在我无济于事了。
心教堂

5

大多数(全部?)框架不提供任何保证,因此假定它们将以随机顺序返回。

始终采取最安全的方法。

例如,java HttpServlet接口: ServletRequest.html#getParameterValues

甚至getParameterMap方法也没有提及参数顺序(java.util.Map迭代器的顺序也不能依赖)。


3

通常,重复的参数值例如

http://example.com/page?field=foo&field=bar

结果是一个单个的queryString参数,它是一个数组:

field[0]=='foo'
field[1]=='bar'

我已经在ASP,ASP.NET和PHP4中看到了这种行为。


确切地说,这是事实上的标准,但据我所知,尚无权威性决定。由于我认为情况并非如此,因此我无能为力。
Stefano Borini,2009年

2
是的,可能每个人都看到了这种行为。问题是,是否确实在某处指定了该位置。
Thilo

-1

我有同样的问题。我在写javascript函数来解析和字符串化查询。我不知道查询字符串是否具有重复的名称或带有方括号的名称(例如x [] = 1&x [] = 2)是否是标准的,尽管某些语言支持这些格式。

但我发现Chrome和Firefox有一个名为的新类URLSeachParams,并且仅支持最简单的格式name=value。如果在查询字符串中有重名,该get方法URLSearchParams只返回第一个。

因此,就个人而言,也许最简单且没有重复的名称url对于将来更加安全。


1
如果查询字符串中的名称重复,则URLSearchParams的get方法仅返回第一个。这是不正确的:您可以使用URLSearchParams.getAll('x')
Blaise

@Blaise非常感谢,我之前误解了该功能。
LCB
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.