Як запобігти подачі форми кілька разів з боку клієнта?


96

Іноді, коли відповідь повільна, можна натиснути кнопку подати кілька разів.

Як запобігти цьому?


4
Я сподіваюся, що причина, по якій ви вказали "сторону клієнта" у назві вашого запитання, полягає в тому, що ви знаєте, що будь-яке рішення для клієнта, щоб уникнути дурних подань, є на 100% небезпечним, і вам завжди слід робити перевірку на стороні сервера.
Паоло Бергантіно

51
Паоло: Так, якщо ви зацікавлені в повній безпеці даних, це слід робити на стороні сервера. Але іноді ви просто хочете завадити бабусі двічі клацнути на кнопку подати, коли їй потрібен лише один клік. У цих випадках JavaScript повністю чудовий.
Simon East

1
Робити це лише на стороні сервера також не є на 100% безпечним, оскільки ваш перший запит може зайняти достатньо часу, щоб закінчити, щоб другий знав, що він не повинен продовжуватися.
igorsantos07

Чи шаблон "Подвійне подання файлів cookie" для запобігання атакам CSRF також не запобігає подачі кількох форм?
Мартін Тома

Відповіді:


99

Використовуйте ненав’язливий javascript, щоб вимкнути подію подання у формі після того, як її вже було надіслано. Ось приклад використання jQuery.

РЕДАГУВАТИ: Виправлена ​​проблема з подачею форми без натискання кнопки надіслати. Дякую, Ічібан.

$("body").on("submit", "form", function() {
    $(this).submit(function() {
        return false;
    });
    return true;
});

4
Що робити, якщо форму подано натисканням клавіші Enter у текстовому полі?
Ічібан

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

Я спробував рішення vanstee разом із ненав’язливою валідацією asp mvc 3, і якщо перевірка клієнта не вдається, код все одно запускається, а подання форми вимкнено назавжди. Я не можу повторно подати після виправлення полів. (див. коментар bjan)

Тож я змінив сценарій vanstee таким чином:

$("form").submit(function () {
    if ($(this).valid()) {
        $(this).submit(function () {
            return false;
        });
        return true;
    }
    else {
        return false;
    }
});

Будь-які інші побічні ефекти, на які слід звернути увагу, чи це вдалося вам застосувати скрізь?
Ciaran Gallagher

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.
Тамас Болварі

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 скрипт блокування викликається першим, а наступним - перевірка, що не призводить до подання, якщо є помилки перевірки
bjan

8

Вимкніть кнопку надсилання незабаром після клацання. Переконайтеся, що правильно обробляєте перевірки. Також зберігайте проміжну сторінку для всіх операцій обробки або БД, а потім перенаправляйте на наступну сторінку. Це гарантує, що оновлення другої сторінки не виконує іншої обробки.


Так, чудова порада Шобан, я згоден. Має бутиform page ---submits to---> form_submission_script.php ---after saving, redirects to---> form_thankyou.html
Саймон Іст

6

Хеш поточного часу, зробіть це прихованим введенням у форму. На стороні сервера перевірте хеш кожної поданої форми; якщо ви вже отримали цей хеш, тоді у вас є повторне подання.

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


Чи не виглядає це "Забагато"? ;-)
Шобан

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 у текстовому полі після відключення кнопки?
Ічібан

Якщо вимкнути таку кнопку, користувач не зможе натиснути ENTER. Але, правда, йому потрібно прив’язати натискання клавіші до введення даних
Борис Гері,

Це заважає кнопці для надсилання. Отже, відключення перевірки на стороні сервера.
Marko Aleksić

@Marko, правильно, але це просив ОП, у будь-якому випадку використання маркера заважало б формі подавати двічі.
Борис Гері

1
Коли я спробував такий спосіб, я виявив, що форма взагалі не надсилається (принаймні, не в Chrome 14), мабуть, тому, що ви відключаєте кнопку до того, як браузер розпочне подання форми.
Simon East

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

4

Найпростіша відповідь на це запитання: "Іноді, коли відповідь повільна, можна кілька разів натиснути кнопку" Надіслати ". Як запобігти цьому?"

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

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

Це вимкне кнопку подати, при першому натисканні для подання. Крім того, якщо у вас є деякі правила перевірки, це буде добре працювати. Сподіваюся, це допоможе.


я думаю, що вам чогось не вистачає, опублікуйте свій код.
Імран Хан

3

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

Але існує проблема із затримкою мережі або ситуацією, коли відключений javascript, коли вам не слід покладатися на JS, щоб цього не сталося.

Отже, на стороні сервера , ви повинні перевірити повторне надсилання від тих самих клієнтів і пропустити повторне, яке здається помилковою спробою користувача.


Я знаю, що на це вже давно відповіли, але чи може хтось пояснити, як затримка мережі може запобігти відключенню? Зараз я маю справу з цією проблемою, і мене дуже бентежить, як форму було надіслано подвійно, навіть якщо я відключив цю кнопку. Я навіть ніколи не думав про те, що JavaScript відключений. Я не думаю, що це проблема в моєму випадку, але тим не менше це цікаве розуміння.
davidatthepark

Я також розглядав можливість регулювання обробника клацань.
davidatthepark

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

Найпростіше та елегантне рішення для мене:

function checkForm(form) // Submit button clicked
{
    form.myButton.disabled = true;
    form.myButton.value = "Please wait...";
    return true;
}

<form method="POST" action="..." onsubmit="return checkForm(this);">
    ...
    <input type="submit" name="myButton" value="Submit">
</form>

Посилання на докладніше ...


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; 

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
Хоча посилання є чудовим, будь ласка, надайте контекст для ваших посилань , оскільки відповідь насправді повинна містити відповідь. Майте на увазі, що бути лише посиланням на зовнішній сайт - це можлива причина, чому і як видаляються деякі відповіді? .
січня

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.