Подтвердить что ты не робот

Заказ значений в HttpServletRequest.getParameterValues ​​()

HttpServletRequest.getParameterValues() возвращает String[], содержащий все значения заданного параметра HTTP-запроса. Кто-нибудь знает, если порядок значений в этом массиве гарантирован спецификацией так же, как и порядок, который эти значения были переданы в запросе?

Например, если у меня есть строка запроса GET x=1&x=2&x=3, я гарантированно получаю String[] {"1", "2", "3"} при вызове getParameterValues()? Кажется, это работает на практике, но я не могу найти ничего, что указывает на то, что это должно быть так, поэтому я неохотно полагаюсь на него.

4b9b3361

Ответ 1

В javadoc для ServletRequest (v2.5 javadoc) ничего не говорится о упорядочении значений для этого метода. Поэтому я не буду полагаться на сохраненный порядок.


Обновление: также проверили спецификационный документ на 2,5, содержит следующую информацию, относящуюся к getParameterValues ​​(). Он ничего не упоминает о заказе в отношении строки запроса, поэтому я думаю, что поведение, которое вы видите, представляет собой деталь реализации, не определенную как часть интерфейса.

Параметры сохраняются как набор пар имя-значение. Множественный параметр значения могут существовать для любого заданного имя параметра. Следующие методы интерфейса ServletRequest: доступный для доступа к параметрам:

  • getParameter
  • getParameterNames
  • getParameterValues ​​
  • getParameterMap

Метод getParameterValues ​​возвращает массив объектов String, содержащий все значения параметров, связанные с имя параметра. Возвращаемое значение из метода getParameter должен быть первое значение в массиве String объекты, возвращенные getParameterValues. Метод getParameterMap возвращает java.util.Map параметра запрос, который содержит имена как ключи и значения параметров в качестве значений карты.

В будущем, спецификации Java Servlet можно загрузить из Sun, я имею в виду сайт Oracle. Вы можете дважды проверить конкретную версию сервлета, которая вас интересует.

Ответ 2

Да, порядок значений, возвращаемых getParamterValues(String), и записи в getParameterMap() гарантированы спецификацией сервлета. Здесь прохождение:

Данные из строки запроса и почтового тела агрегируются в запрос параметров. Строка запроса данные представлены перед телом данные. Например, если запрос сделанный с помощью строки запроса a = hello и почтовое тело a = goodbye & a = world, результирующий набор параметров будет упорядоченный a = (привет, до свидания, мир).

(Это из раздела "Параметры протокола HTTP" в главе "Запрос" в спецификациях сервлета (SRV.4.1 в версии 2.4, SRV.3.1 в версии 2.5).

Как представляется, нет чистого способа получить имена в порядке (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>

Ответ 3

Это действительно не определено явно в спецификации Servlet, но, по крайней мере, спецификация HTML-форм явно определяет его в application/x-www-form-urlencoded:

2. Названия/значения управления перечислены в том порядке, в котором они отображаются в документе.

Итак, эта часть безопасна. Теперь servletcontainer, наиболее логично достойная и эффективная реализация, будет обрабатывать поток ввода HTTP сразу же, когда он поступит, поэтому параметры будут обрабатываться в том порядке, в каком они появляются в URI запроса (GET) или в теле запроса (POST). Сбор их в String[] является самым простым выбором, так как он также используется как в API-интерфейсе Servlet, поэтому я действительно не вижу причин собирать его в структуре типа 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[], хотя это явно не указано в 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 + "]"));
}

Ответ 4

У меня возникла проблема в извлечении карты param-value из HttpServletRequest в порядке, соответствующем элементам JSP. Я написал OrderedRequestMap, который анализирует тело запроса POST приложения /x -www-form-urlencoded.

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());

Надеюсь, это поможет.

Ответ 5

Это зависит от реализации интерфейса HttpServletRequest.