Отправка формы 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..." />
</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. Он используетURL
API, который поддерживается везде, кроме 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".