在HttpServletRequest.getParameterValues()中排序值

ska*_*man 21 java servlets http

HttpServletRequest.getParameterValues()返回String[]包含给定HTTP请求参数的所有值的a.有没有人知道这个数组中的值的顺序是否由规范保证与请求中传递这些值的顺序相同?

例如,如果我有GET查询字符串x=1&x=2&x=3,我保证在收到String[] {"1", "2", "3"}电话时收到getParameterValues()吗?它似乎在实践中起作用,但我找不到任何指定必须如此的情况,所以我不愿意依赖它.

bra*_*ter 15

ServletRequest的javadoc(v2.5 javadoc)没有提到有关该方法的值排序的任何内容.因此,我不会依赖于保留的顺序.


更新:还检查了2.5的spec文档,包含有关getParameterValues()的以下信息.它没有提到关于查询字符串的排序,所以我认为你看到的行为是实现细节,没有被定义为接口的一部分.

参数存储为一组名称 - 值对.对于任何给定的参数名称,可以存在多个参数值.ServletRequest接口的以下方法可用于访问参数:

  • 的getParameter
  • getParameterNames
  • getParameterValues
  • getParameterMap

getParameterValues方法返回一个String对象数组,其中包含与参数名称关联的所有参数值.getParameter方法返回的值必须是getParameterValues返回的String对象数组中的第一个值.getParameterMap方法返回请求参数的java.util.Map,其中包含名称作为键,参数值包含映射值.

为了将来参考,Java Servlet规范可以从Sun下载,我的意思是Oracle的网站.您可以仔细检查您感兴趣的特定servlet版本.


yon*_*ran 11

是的,值的顺序返回通过getParamterValues(String)并在条目getParameterMap() 由Servlet规格保证.这是段落:

来自查询字符串和帖子正文的数据被聚合到请求参数集中.查询字符串数据在帖子正文数据之前显示.例如,如果使用a = hello的查询字符串和a = goodbye&a = world的帖子主体发出请求,则生成的参数集将被排序为a =(hello,goodbye,world).

(这来自Servlet规范的"请求"一章中的"HTTP协议参数"部分(版本2.4中的SRV.4.1,版本2.5中的SRV.3.1).)

没有似乎是一个干净的方式来获得,以便(名称getParameterNames()没有在顺序返回名称,浏览器了).我想,我可以解析原始的GET字符串getQueryString()或解析原始的POST字符串getInputStream(),但我认为我会添加另一个隐藏的参数,然后用它getParameterValues(String)来获取它的顺序.

如果你好奇我为什么要按顺序参数,那是因为我有控件,用户可以使用jQuery重新排列,我想知道用户选择的顺序:

<form>
  <ul id=variables>
    <li>
      <input name=hello>hello
      <input type=hidden name=variableOrder value=hello>
    <li>
      <input name=world>world
      <input type=hidden name=variableOrder value=world>
  </ul>
</form>
<script src="jquery.js"></script>
<script src="jquery-ui.js"></script>
<script>
  jQuery('#variables').sortable().disableSelection();
</script>
Run Code Online (Sandbox Code Playgroud)

  • 这没有(明确地)说明查​​询字符串数据或帖子主体数据中的排序,只有`post body data`应出现在`query string data`之后.示例中隐含了完整的保证,参考实现遵循原始顺序,但...... (5认同)

Bal*_*usC 8

它确实没有在Servlet规范中明确定义,但至少HTML表单规范明确地在application/x-www-form-urlencoded部分中定义它:

2.控件名称/值按它们在文档中出现的顺序列出.

所以,那部分是安全的.现在servletcontainer,大多数逻辑上是一个体面和有效的实现将在它进入时立即处理HTTP输入流,因此参数将按照它们出现在请求URI(GET)或请求体(POST)中的顺序进行处理.在a中收集它们String[]是最直接的选择,因为它也在Servlet API中原样使用,所以我真的没有看到任何理由首先在HashSet类似的结构中收集它,或者做一个Collections#shuffle()或者其他什么,然后将它转换为String[]然后.

我至少可以从经验中看出,Tomcat是以正确的方式做到的,因此构建在Tomcat/Catalina(IBM Websphere,JBoss AS,Sun Glassfish等)之上的所有主要容器/应用程序也将表现得如此.我只是没有掌握Weblogic的经验,但如果它以不同的方式处理它会让我感到惊讶(阅读:效率较低).

从逻辑上讲,只保证参数名称的顺序,因为它由a支持HashMap.


总结:参数收集在一个HashMap<String, String[]>.由于其性质,保证名称不被命令HashMap.然而,值(一个参数名称可以具有多个值,例如foo=bar1&foo=bar2&foo=bar3)由于其性质而被排序String[],尽管这在Servlet API中没有明确指定.

为了安全起见,您希望使用不同的方法,例如

foos=3&foo[0]=bar1&foo[1]=bar2&foo[2]=bar3
Run Code Online (Sandbox Code Playgroud)

int foos = Integer.valueOf(request.getParameter("foos"));
for (int i = 0; i < foos; i++) {
    int foo = Integer.valueOf(request.getParameter("foo[" + i + "]"));
}
Run Code Online (Sandbox Code Playgroud)

  • Servlet规范确实应该强制执行订单.这将使具有多个值的参数更有用,因为您可以关联来自表行的相关参数. (4认同)
  • 依赖于Servlet规范未强制要求的东西是恕我直言,这是一个错误.如果您这样做,您只需承担风险,使您的应用程序不可移植.当然,人们可以争论容器实现效率不高但不改变任何东西,最终的期望是错误的(无论有多少实现使用Tomcat). (2认同)