Как предотвратить многократную отправку формы со стороны клиента?

96

Иногда, когда ответ медленный, можно несколько раз нажать кнопку отправки.

Как этого не допустить?

О, мой бог
источник
4
Я надеюсь, что причина, по которой вы указали «клиентскую сторону» в заголовке своего вопроса, заключается в том, что вы знаете, что любое решение на клиенте, позволяющее избежать ложных представлений, на 100% небезопасно, и вам всегда следует выполнять проверку на стороне сервера.
Паоло Бергантино,
51
Паоло: Да, если вас интересует полная безопасность данных, это нужно делать на стороне сервера. Но иногда вы просто хотите запретить бабушке дважды щелкнуть кнопку отправки, когда для этого нужен только один щелчок. В этих случаях javascript вполне подойдет.
Саймон Ист
1
Выполнение этого только на стороне сервера также не на 100% безопасно, так как ваш первый запрос может занять достаточно много времени для завершения, поэтому второй будет знать, что он не должен выполняться.
igorsantos07 06
Разве шаблон cookie Double-Submit для предотвращения атак CSRF также не предотвращает многократную отправку форм?
Мартин Тома

Ответы:

99

Используйте ненавязчивый javascript, чтобы отключить событие отправки в форме после того, как оно уже было отправлено. Вот пример использования jQuery.

РЕДАКТИРОВАТЬ: исправлена ​​проблема с отправкой формы без нажатия кнопки отправки. Спасибо, Ичибан.

$("body").on("submit", "form", function() {
    $(this).submit(function() {
        return false;
    });
    return true;
});
Starx
источник
4
Что делать, если форма отправляется нажатием клавиши ввода в текстовом поле?
ichiban
2
Вам вообще нужен return true? Я думаю, что первоначальная отправка должна работать и без этого.
Саймон Ист
Я считаю, что return trueподразумевается, если опущено.
Дерек
15
Я пробовал это решение с ненавязчивой проверкой и MVC. Сначала вызывается JS, который всегда возвращает false, а затем вызывается проверка. Поэтому, если в моей форме есть ошибка проверки, форма никогда не отправляется !!
bjan
6
действительно отлично работает. Я также хотел бы отключить кнопку отправки и заменить текст кнопки отправки, чтобы показать подсказку пользователя. $(this).find("input[type='submit']").attr('disabled', 'disabled').val('submiting'); return true; });
Cam Song
42

Я попробовал решение Вансти вместе с ненавязчивой проверкой asp mvc 3, и если проверка клиента не удалась, код все равно будет запущен, а формы отключена навсегда. Я не могу отправить заявку повторно после исправления полей. (см. комментарий bjan)

Поэтому я модифицировал сценарий Вансти следующим образом:

$("form").submit(function () {
    if ($(this).valid()) {
        $(this).submit(function () {
            return false;
        });
        return true;
    }
    else {
        return false;
    }
});
м ирина
источник
Есть ли другие побочные эффекты, которые следует отметить, или это сработало для вас, чтобы применить везде?
Кьяран Галлахер
24

Управление отправкой формы на стороне клиента может быть реализовано довольно элегантно, если обработчик onsubmit скроет кнопку отправки и заменит ее анимацией загрузки. Таким образом, пользователь получает немедленную визуальную обратную связь в том же месте, где произошло его действие (щелчок). В то же время вы предотвращаете отправку формы в другой раз.

Если вы отправляете форму через XHR, имейте в виду, что вам также необходимо обрабатывать ошибки отправки, например тайм-аут. Вам придется снова отобразить кнопку отправки, потому что пользователю необходимо повторно отправить форму.

С другой стороны, llimllib поднимает очень важный вопрос. Вся проверка формы должна происходить на стороне сервера. Это включает в себя несколько проверок отправки. Никогда не доверяйте клиенту! Это не только случай, если отключен javascript. Вы должны иметь в виду, что весь код на стороне клиента можно изменять. Это довольно сложно представить, но html / javascript, обращающийся к вашему серверу, не обязательно является написанным вами html / javascript.

Как предлагает llimllib, сгенерируйте форму с идентификатором, уникальным для этой формы, и поместите его в скрытое поле ввода. Сохраните этот идентификатор. При получении данных формы обрабатывать их только при совпадении идентификатора. (Также связать идентификатор с сеансом пользователя и сопоставить его также для дополнительной безопасности.) После обработки данных удалите идентификатор.

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

Роб
источник
15
<form onsubmit="if(submitted) return false; submitted = true; return true">
хаос
источник
6
Использование <form onsubmit="return (typeof submitted == 'undefined') ? (submitted = true) : !submitted">или записи var submitted = false;в нужный момент вашего скрипта, чтобы избежать следующее сообщение об ошибке: Uncaught ReferenceError: submitted is not defined.
Tamás Bolvári
15

Вот простой способ сделать это:

<form onsubmit="return checkBeforeSubmit()">
  some input:<input type="text">
  <input type="submit" value="submit" />
</form>

<script type="text/javascript">
  var wasSubmitted = false;    
    function checkBeforeSubmit(){
      if(!wasSubmitted) {
        wasSubmitted = true;
        return wasSubmitted;
      }
      return false;
    }    
</script>
ичибан
источник
с ненавязчивой проверкой jQuery сначала
вызывается
8

Отключите кнопку отправки сразу после щелчка. Убедитесь, что вы правильно обрабатываете проверки. Также сохраните промежуточную страницу для всех операций обработки или БД, а затем перенаправьте на следующую страницу. Это гарантирует, что обновление второй страницы не повлечет за собой другую обработку.

Шобан
источник
Ага, отличный отзыв Шобан, согласен. Должно бытьform page ---submits to---> form_submission_script.php ---after saving, redirects to---> form_thankyou.html
Саймон Ист
6

Хешируйте текущее время, сделайте его скрытым вводом в форме. На стороне сервера проверяйте хэш каждой отправки формы; если вы уже получили этот хэш, значит, вы получили повторную отправку.

изменить: полагаться на javascript - не лучшая идея, поэтому вы все можете продолжать голосовать за эти идеи, но у некоторых пользователей она не будет включена. Правильный ответ - не доверять вводу пользователя на стороне сервера.

llimllib
источник
Разве это не выглядит "слишком много"? ;-)
Шобан
1
Похоже, это просто помешает пользователю отправлять форму чаще, чем один раз в секунду. Если я отправлю форму в 2009-05-29 12:13:37, то сервер не позволит мне отправить другую форму с тем же хешем, но если я нажму «Отправить» в 2009-05-29 12:13:38, это пройдет. Кроме того, ваша методика не позволит двум разным пользователям одновременно отправлять две разные формы: один из них будет исключен, даже если это, возможно, будет первая отправка от него.
Sarah Vessels,
2
@moneypenny ваше первое возражение является ложным, хеш будет указывать на время отправки формы пользователю, а не на время отправки. Если вы действительно беспокоитесь о втором, у вас есть множество вариантов. Добавьте их идентификатор сеанса в строку, которую вы хешируете, и / или проверьте все поля формы на точное совпадение; два пользователя, вероятно, отправили не одну и ту же форму.
llimllib
@Shoban Мне очень жаль, я не понимаю, что вы говорите
llimllib
2
«Чрезмерное» - в глазах смотрящего. Если вам действительно нужно предотвратить дублирование отправки формы, по крайней мере, часть решения должна быть на стороне сервера. «Пользователям нельзя доверять».
Бен Бланк,
5

Вы также можете отобразить индикатор выполнения или счетчик, чтобы указать, что форма обрабатывается.

Тони Борф
источник
5

Используя JQuery, вы можете:

$('input:submit').click( function() { this.disabled = true } );

&

   $('input:submit').keypress( function(e) {
     if (e.which == 13) {
        this.disabled = true 
     } 
    }
   );
Борис Гери
источник
1
Что делать, если форма отправляется нажатием клавиши ENTER в текстовом поле после того, как кнопка отключена?
ichiban
Отключение такой кнопки не позволит пользователю затем нажать ENTER. Но, верно, ему нужно привязать нажатие клавиши к вводу отправки
Борис Гери
Это предотвращает отправку кнопки. Следовательно, отключение проверки на стороне сервера.
Марко Алексич
@Marko, верно, но это запрос OP, в любом случае использование токена предотвратит отправку формы дважды.
Борис Гери
1
Когда я попробовал эту технику, я обнаружил, что форма вообще не отправляется (по крайней мере, в Chrome 14), предположительно потому, что вы отключили кнопку до того, как браузер запустит отправку формы.
Саймон Ист
4

Я знаю, что вы пометили свой вопрос с помощью javascript, но вот решение, которое вообще не зависит от javascript:

Это шаблон веб-приложения под названием PRG , и вот хорошая статья , описывающая его.

Пабло Фернандес
источник
4

Вы можете предотвратить множественную отправку просто с помощью:

var Workin = false;

$('form').submit(function()
{
   if(Workin) return false;
   Workin =true;

   // codes here.
   // Once you finish turn the Workin variable into false 
   // to enable the submit event again
   Workin = false;

});
Альфа
источник
Проблема с вашим ответом заключается в том, что между временем, когда пользователь нажимает, и временем Workin =true; . Двойные сабмиты по-прежнему возможны, но их меньше.
sent1nel 07
4

Самый простой ответ на этот вопрос: «Иногда, когда ответ медленный, можно нажимать кнопку отправки несколько раз. Как предотвратить это?»

Просто отключите кнопку отправки формы, как показано ниже.

<form ... onsubmit="buttonName.disabled=true; return true;">
  <input type="submit" name="buttonName" value="Submit">
</form>

Это отключит кнопку отправки при первом нажатии для отправки. Также, если у вас есть некоторые правила проверки, он будет работать нормально. Надеюсь, это поможет.

Имран Хан
источник
Я думаю, вам чего-то не хватает, пожалуйста, разместите свой код.
Имран Хан
3

На стороне клиента вы должны отключить кнопку отправки после того, как форма будет отправлена ​​с кодом javascript, например, как метод, предоставляемый @vanstee и @chaos.

Но существует проблема из-за задержки сети или ситуации с отключенным javascript, когда вы не должны полагаться на JS, чтобы этого не произошло.

Итак, на стороне сервера вы должны проверить повторную отправку от одних и тех же клиентов и опустить повторяющуюся, которая кажется ложной попыткой со стороны пользователя.

Steveyang
источник
Я знаю, что на это давным-давно ответили, но может ли кто-нибудь объяснить, как задержка сети может предотвратить отключение? Я занимаюсь этой проблемой прямо сейчас, и меня очень смущает, как форма была отправлена ​​дважды, хотя я отключил кнопку. Я даже не думал об отключении JavaScript. Я не думаю, что это проблема в моем случае, но, тем не менее, это интересный вывод.
davidatthepark
Я также рассматривал возможность регулирования обработчика кликов.
davidatthepark
Как бы вы проверили сторону сервера, если отправка от того же клиента? По IP-адресу пользователя? Если да, то где бы вы «сохранили» IP-адрес на стороне сервера из ранее отправленной записи? (я использую узел, если этот контекст требуется)
user1063287
3

Вы можете попробовать плагин safeform jquery.

$('#example').safeform({
    timeout: 5000, // disable form on 5 sec. after submit
    submit: function(event) {
        // put here validation and ajax stuff...

        // no need to wait for timeout, re-enable the form ASAP
        $(this).safeform('complete');
        return false;
    }
})
Макс Каменков
источник
1

Используйте этот код в своей форме. Он будет обрабатывать несколько кликов.

<script type="text/javascript">
    $(document).ready(function() {
        $("form").submit(function() {
            $(this).submit(function() {
                return false;
            });
            return true;
        });     
    }); 
</script>

точно будет работать.

Бача
источник
1

Это позволяет отправлять каждые 2 секунды. В случае предварительной проверки.

$(document).ready(function() {
    $('form[debounce]').submit(function(e) {
        const submiting = !!$(this).data('submiting');

        if(!submiting) {
            $(this).data('submiting', true);

            setTimeout(() => {
                $(this).data('submiting', false);
            }, 2000);

            return true;
        }

        e.preventDefault();
        return false;
    });
})
Аурел
источник
0

лучший способ предотвратить отправку нескольких - просто передать идентификатор кнопки в метод.

    function DisableButton() {
        document.getElementById("btnPostJob").disabled = true;
    }
    window.onbeforeunload = DisableButton; 
user2427182
источник
0

Сделать это с помощью javascript немного проще. Ниже приведен код, обеспечивающий желаемую функциональность:

$('#disable').on('click', function(){
    $('#disable').attr("disabled", true);
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="disable">Disable Me!</button>

Риш
источник
0

Самое простое решение - отключить кнопку при нажатии, включить ее после завершения операции. Чтобы проверить аналогичное решение на jsfiddle:

[click here][1]

И вы можете найти другое решение по этому поводу .

Каляни
источник
1
Хотя ссылка хороша, пожалуйста, предоставьте контекст для вашей ссылки (-ов) , так как ответ на самом деле должен содержать ответ. Имейте в виду, что возможная причина того, почему и как удаляются некоторые ответы, - это просто ссылка на внешний сайт ? .
Jan
0

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

<button id="submit" type="submit" onclick="submitLimit()">Yes</button>

function submitLimit() {
var btn = document.getElementById('submit')
setTimeout(function() {
    btn.setAttribute('disabled', 'disabled');
}, 1);

setTimeout(function() {
    btn.removeAttribute('disabled');
}, 2000);}

В ECMA6 Syntex

function submitLimit() {
submitBtn = document.getElementById('submit');

setTimeout(() => { submitBtn.setAttribute('disabled', 'disabled') }, 1);

setTimeout(() => { submitBtn.removeAttribute('disabled') }, 4000);}
Аваис Джамиль
источник
0

Просто чтобы добавить к возможным ответам без обхода проверки ввода в браузере

$( document ).ready(function() {
    $('.btn-submit').on('click', function() {
        if(this.form.checkValidity()) {
            $(this).attr("disabled", "disabled");
            $(this).val("Submitting...");
            this.form.submit();
        }
    });
});
Roi
источник
0

Альтернатива тому, что предлагалось ранее:

jQuery('form').submit(function(){
     $(this).find(':submit').attr( 'disabled','disabled' );
     //the rest of your code
});
Кисдед Саби - CodeRevolution
источник