Отправка формы GET с параметрами строки запроса и скрытыми параметрами исчезает

Рассмотрим эту форму:

<form action="http://www.blabla.com?a=1&b=2" method="GET">
    <input type="hidden" name="c" value="3" /> 
</form>

При отправке этой формы (формы GET) параметры a и b исчезают. Есть ли причина для этого? Есть ли способ избежать этого поведения?

14 ответов

Разве не для этого нужны скрытые параметры...?

<form action="http://www.example.com" method="GET">
  <input type="hidden" name="a" value="1" /> 
  <input type="hidden" name="b" value="2" /> 
  <input type="hidden" name="c" value="3" /> 
  <input type="submit" /> 
</form>

Я бы не стал рассчитывать, что какой-либо браузер сохранит существующую строку запроса в URL-адресе действия.

В спецификациях ( RFC1866, стр. 46; HTML 4.x раздел 17.13.3) указано:

Если метод "get", а action - HTTP URI, пользовательский агент принимает значение action и добавляет `?' к нему затем добавляется набор данных формы, закодированный с использованием типа контента application/x-www-form-urlencoded.

Возможно, кто-то может кодировать URL-адрес действия для встраивания знака вопроса и параметров, а затем скрестить пальцы, надеясь, что все браузеры оставят этот URL-адрес как есть (и подтвердит, что сервер его тоже понимает). Но я бы никогда не положился на это.

Кстати, это не отличается для не скрытых полей формы. Для POST URL действия может содержать строку запроса.

В HTML5 это поведение для каждой спецификации.

См. http://www.w3.org/TR/2011/WD-html5-20110525/association-of-controls-and-forms.html

Посмотрите на "4.10.22.3 Алгоритм отправки формы", шаг 17. В случае формы GET для http/s URI со строкой запроса:

Пусть destination будет новый URL, равный действию, за исключением того, что его <query> Компонент заменяется запросом (при необходимости добавляется символ U+003F QUESTION MARK (?)).

Таким образом, ваш браузер удалит существующую часть "?..." в вашем URI и заменит ее новой на основе вашей формы.

В HTML 4.01 спецификация создает недопустимые URI - хотя большинство браузеров на самом деле этого не делают..

См. http://www.w3.org/TR/html401/interact/forms.html, шаг четвертый - URI будет иметь? добавлено, даже если оно уже содержит.

То, что вы можете сделать, это использовать простой foreach для таблицы, содержащей информацию GET. Например в php:

foreach ($_GET as $key => $value) {
    echo("<input type='hidden' name='$key' value='$value'/>");
}

Вы должны включить два элемента (a и b) в качестве скрытых элементов ввода, а также C.

У меня была очень похожая проблема, когда для формы действия у меня было что-то вроде:

<form action="http://www.example.com/?q=content/something" method="GET">
   <input type="submit" value="Go away..." />&nbsp;
</form>

Кнопка доставит пользователя на сайт, но информация о запросе исчезла, поэтому пользователь попал на домашнюю страницу, а не на нужную страницу контента. Решение в моем случае состояло в том, чтобы выяснить, как закодировать URL-адрес без запроса, который приведет пользователя на нужную страницу. В этом случае моей целью был сайт Drupal, так что, как оказалось, /content/something тоже сработало. Я также мог бы использовать номер узла (т.е. /node/123).

Ваше строительство незаконно. Вы не можете включить параметры в значение действия формы. Что произойдет, если вы попытаетесь это сделать, будет зависеть от особенностей браузера. Я не удивлюсь, если он работает с одним браузером, а не с другим. Даже если бы это работало, я бы не стал полагаться на это, потому что следующая версия браузера может изменить поведение.

"Но допустим, у меня есть параметры в строке запроса и в скрытых входах, что я могу сделать?" Что вы можете сделать, это исправить ошибку. Не быть глупым, но это немного похоже на вопрос: "Но допустим, что мой URL использует знаки процента вместо косой черты, что я могу сделать?" Единственный возможный ответ - вы можете исправить URL.

Когда исходный запрос имеет массив, для php:

      foreach (explode("\n", http_build_query($query, '', "\n")) as $keyValue) {
    [$key, $value] = explode('=', $keyValue, 2);
    $key = htmlspecialchars(urldecode($key), ENT_COMPAT | ENT_HTML5);
    $value = htmlspecialchars(urldecode($value), ENT_COMPAT | ENT_HTML5);
    echo '<input type="hidden" name="' . $key . '" value="' . $value . '"' . "/>\n";
}

Чтобы ответить на ваш первый вопрос , да, браузер делает это, и причина в том, что браузер не заботится о существующих параметрах в URL-адресе действия , поэтому он полностью удаляет их .

и чтобы этого не произошло, используйте эту функцию JavaScript, которую я написал с помощью jQuery в:

      function addQueryStringAsHidden(form){
    if (form.attr("action") === undefined){
        throw "form does not have action attribute"
    }

    let url = form.attr("action");
    if (url.includes("?") === false) return false;
    
    let index = url.indexOf("?");
    let action = url.slice(0, index)
    let params = url.slice(index);
    url = new URLSearchParams(params);
    for (param of url.keys()){
        let paramValue = url.get(param);
        let attrObject = {"type":"hidden", "name":param, "value":paramValue};
        let hidden = $("<input>").attr(attrObject);
        form.append(hidden);
    }
    form.attr("action", action)
}

Мое наблюдение

  • когда метод GET и форма отправлена, скрытый элемент ввода был отправлен как параметр запроса. Старые параметры URL-адреса действия были стерты. Таким образом, в этом случае данные формы заменяют строку запроса в URL-адресе действия.

  • Когда метод POST и форма отправлена, параметры запроса в URL-адресе действия были неповрежденными (req.query), а данные элемента ввода были отправлены как данные формы (req.body)

Короче говоря, если вы хотите передать параметры запроса, а также данные формы, используйте атрибут метода как «POST»

Вот простой пример JavaScript, позволяющий сохранить существующие строки запроса при отправке формы GET. Он используетURLAPI, который поддерживается везде, кроме IE.

      const form = document.querySelector('form');

form.addEventListener('submit', (e) => {
  e.preventDefault();
  
  const form = e.currentTarget;
  const { action } = form;
  const to = new URL(action, location);
  const formData = new FormData(form);
  
  for (const [k, v] of formData.entries())
    to.searchParams.append(k, v);

  location.href = String(to);
});

Основным недостатком этого решения является то, что пользователи с отключенным JavaScript будут возвращаться к удалению существующих строк запроса действия их формы.

Если вам нужен обходной путь, так как эту форму можно разместить в сторонних системах, вы можете использовать Apache mod_rewrite следующим образом:

RewriteRule ^dummy.link$ index.php?a=1&b=2 [QSA,L]

тогда ваша новая форма будет выглядеть так:

<form ... action="http:/www.blabla.com/dummy.link" method="GET">
<input type="hidden" name="c" value="3" /> 
</form>

и Apache добавит 3-й параметр к запросу

Это в ответ на вышеупомянутый пост Efx:

Если URL-адрес уже содержит переменную, которую вы хотите изменить, он снова добавляется как скрытое поле.

Вот модификация этого кода для предотвращения дублирования переменных в URL:

foreach ($_GET as $key => $value) {
    if ($key != "my_key") {
        echo("<input type='hidden' name='$key' value='$value'/>");
    }
}

Я обычно пишу что-то вроде этого:

foreach($_GET as $key=>$content){
        echo "<input type='hidden' name='$key' value='$content'/>";
}

Это работает, но не забывайте очищать свои входные данные от атак XSS!

<form ... action="http:/www.blabla.com?a=1&b=2" method ="POST">
<input type="hidden" name="c" value="3" /> 
</form>

измените метод запроса на "POST" вместо "GET".

Другие вопросы по тегам