2010-02-23 41 views
19

HttpServletRequest.getParameterValues()返回包含給定HTTP請求參數的所有值的String[]。有誰知道這個數組中的值的順序是否由規範保證,與這些值在請求中傳遞的順序相同?HttpServletRequest.getParameterValues()中的值的排序

舉例來說,如果我有GET查詢字符串x=1&x=2&x=3,我是保證接收String[] {"1", "2", "3"}當我打電話getParameterValues()?它似乎在實踐中發揮作用,但我找不到任何明確說明這一點的事情,所以我不願意依賴它。

+1

由於HttpServletRequest是一個接口,它依賴於它的實現。 雖然我會很驚訝,如果有一個實現不返回收到的順序的值。 – Fortega 2010-02-23 10:32:13

+0

接口文檔*可以*規定行爲,如果設計師如此選擇,但在這種情況下,他們沒有。 – skaffman 2010-02-23 10:39:03

回答

13

ServletRequest的javadoc(v2.5 javadoc)沒有提及任何關於該方法的值排序的內容。因此,我不會依賴保存的命令。


更新:也檢查了spec文檔2.5,包含以下有關getParameterValues()的信息。它沒有提到有關查詢字符串排序的任何內容,所以我認爲您所看到的行爲是實現細節,而不是定義爲接口的一部分。

參數作爲一組 名稱 - 值對存儲。對於任何給定的 參數名稱,可以存在多個參數 值。所述的ServletRequest接口的以下方法 是 可訪問參數:

  • 的getParameter
  • getParameterNames
  • getParameterValues
  • getParameterMap

的 getParameterVa lues方法返回一個包含所有 參數值的字符串對象數組 ,該參數值與 參數名稱相關聯。從getParameter方法返回的值 必須爲 String 對象返回的數組中的第一個值 getParameterValues。 getParameterMap方法返回 請求參數的 java.util.Map,其中包含名稱作爲鍵 和參數值作爲映射值。

爲了將來的參考,可以從Sun, I mean Oracle's website下載Java Servlet規範。您可以仔細檢查您感興趣的特定servlet版本。

7

它確實沒有明確definied在Servlet規範,但至少HTML形式符合規範definies它明確地在application/x-www-form-urlencoded部分:/值的順序列出

2.控制的名字出現在該文件。

所以,那部分是安全的。現在,servlet容器在邏輯上是一個體面和高效的實現,它將在HTTP輸入流進入時立即處理,所以這些參數將按照它們出現在請求URI(GET)或請求體(POST)中的順序進行處理。收集他們在String[]是最直接的選擇,因爲它也是在Servlet API中原樣使用的,所以我真的沒有看到任何理由首先在HashSet類似的結構中收集它,或者做一個Collections#shuffle()或其他什麼,然後之後將其轉換爲String[]

我至少可以從經驗中瞭解到,Tomcat是正確的,因此所有在Tomcat/Catalina(IBM Websphere,JBoss AS,Sun Glassfish等)上構建的主要容器/應用程序也將表現如此。我只是沒有Weblogic的經驗,但如果它以不同的方式處理它,我會感到驚訝(閱讀:效率較低)。

只有參數名稱的順序不能保證,因爲它是由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 

int foos = Integer.valueOf(request.getParameter("foos")); 
for (int i = 0; i < foos; i++) { 
    int foo = Integer.valueOf(request.getParameter("foo[" + i + "]")); 
} 
+2

依賴於Servlet規範未授權的內容,恕我直言,這是一個錯誤。如果你這樣做,你只需承擔風險,使你的應用程序不可移植。當然,人們可以爭論容器實現不是有效的,但不會改變任何事情,最終期望錯誤(不管有多少實現使用Tomcat)。 – 2010-02-23 17:28:27

+0

這是一個角落案件。 – BalusC 2010-02-23 18:19:50

+2

Servlet Spec確實應該執行一個命令。這會使具有多個值的參數更有用,因爲例如可以關聯表格行中的相關參數。 – Ryan 2011-11-17 14:48:40

0

它依賴於HttpServletRequest的接口實現。

+8

你爲什麼重複已經給出的評論/回答?請添加一些新的或只是upvote你同意的答案,並沿着:) – BalusC 2010-02-23 17:44:57

10

是,通過getParamterValues(String)返回和值的條目的在getParameterMap()的順序是由 Servlet規範保證。這裏的通道:

從查詢字符串數據和 後身體都彙總到 請求參數集。查詢字符串 數據在郵件正文前 數據。例如,如果一個請求是 ,用查詢字符串a = hello 和post體a = goodbye & a = world, 生成的參數集將爲 ,那麼命令a =(hello,goodbye,world)。

(這是從內部 「請求」 在Servlet規格的章節(2.4版本SRV.4.1,SRV.3.1版本2.5)中的 「HTTP協議參數」 部分。)

不是似乎是一個乾淨的方式來獲取名稱的順序(getParameterNames()確實不是返回名稱的瀏覽器給出的順序)。我可以,我想,從getQueryString()解析原始GET字符串或從getInputStream()解析原始POST字符串,但相反,我想我會添加另一個隱藏參數,然後使用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> 
+5

這並不(明確)說查詢字符串數據或後主體數據內的排序任何事情,只有'後主體數據'應該出現在'查詢字符串數據「。示例中包含完整的保證,參考實現尊重原始的順序,但... – beetstra 2012-03-07 19:56:22

2

根據JSP上的元素,我有一個問題需要從HttpServletRequest中提取參數值映射。我寫了一個OrderedRequestMap,用於解析application/x-www-form-urlencoded POST請求體。

import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.UnsupportedEncodingException; 
import java.net.URLDecoder; 
import java.util.Arrays; 
import java.util.LinkedHashMap; 
import java.util.Map; 


public class OrderedRequestMap extends LinkedHashMap<String,String[]> { 

private final String encoding; 

public OrderedRequestMap(InputStream httpBody, String encoding) throws IOException { 
    this.encoding = encoding; 
    fill(httpBody); 
} 

private void fill(InputStream is) throws IOException { 
    final InputStreamReader reader = new InputStreamReader(is, "ASCII"); 
    int c; 
    StringBuilder sb = new StringBuilder(1000); 
    while ((c = reader.read()) != -1) { 
     char ch = (char)c; 
     if (ch == '&') { 
      put(sb.toString()); 
      sb = new StringBuilder(1000); 
     } else { 
      sb.append(ch); 
     } 
    } 
    put(sb.toString()); 
} 

private void put(String parameter) throws UnsupportedEncodingException { 
    String[] pair = parameter.split("="); 
    if (pair.length == 0) 
     return; 
    String key = URLDecoder.decode(pair[0], encoding); 
    String val = EMPTY_STR; 
    if (pair.length > 1) 
     val = URLDecoder.decode(pair[1], encoding); 
    String[] values = get(key); 
    if (values == null) 
     values = new String[]{val}; 
    else { 
     values = Arrays.copyOf(values, values.length+1); 
     values[values.length - 1] = val; 
    } 
    put(key, values); 
} 


private static final String EMPTY_STR = ""; 
} 

,並調用它像這樣

new OrderedRequestMap(request.getInputStream(), request.getCharacterEncoding()); 

希望,它幫助。