Come impedire che il modulo venga inviato più volte dal lato client?


96

A volte, quando la risposta è lenta, è possibile fare clic più volte sul pulsante di invio.

Come evitare che ciò accada?


4
Spero che il motivo per cui metti "lato client" nel titolo della tua domanda è perché sei consapevole che qualsiasi soluzione sul client per cercare di evitare invii ingannevoli è insicura al 100% e dovresti sempre eseguire la convalida sul lato server.
Paolo Bergantino

51
Paolo: Sì, se sei interessato alla completa sicurezza dei dati, dovrebbe essere fatto lato server. Ma a volte vuoi solo impedire alla nonna di fare doppio clic sul pulsante di invio quando è necessario un solo clic. In questi casi javascript va benissimo.
Simon East

1
Farlo solo lato server non è sicuro al 100%, poiché la tua prima richiesta potrebbe richiedere abbastanza tempo per essere completata in modo che la seconda sappia che non dovrebbe procedere.
igorsantos07

Il Double-Submit Cookie Pattern per prevenire attacchi CSRF non impedisce anche l'invio di più moduli?
Martin Thoma

Risposte:


99

Usa javascript discreto per disabilitare l'evento di invio sul modulo dopo che è già stato inviato. Ecco un esempio che utilizza jQuery.

EDIT: risolto il problema con l'invio di un modulo senza fare clic sul pulsante di invio. Grazie, ichiban.

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

4
Cosa succede se il modulo viene inviato premendo Invio in una casella di testo?
ichiban

2
Hai anche bisogno del return true? Penso che l'invio iniziale dovrebbe funzionare senza quello.
Simon East

Credo che return truesia implicito se omesso.
Derek

15
Ho provato questa soluzione con convalida discreta e MVC. Il JS viene chiamato prima che restituisce sempre false e quindi viene chiamata la convalida. Quindi, se il mio modulo ha qualche errore di convalida, il modulo non viene mai inviato !!
bjan

6
funziona davvero alla grande. Mi piace anche disabilitare il pulsante di invio e sostituire il testo del pulsante di invio per mostrare anche il suggerimento dell'utente. $(this).find("input[type='submit']").attr('disabled', 'disabled').val('submiting'); return true; });
Cam Song

42

Ho provato la soluzione di Vanstee insieme alla convalida discreta di asp mvc 3 e se la convalida del client fallisce, il codice viene ancora eseguito e l'invio del modulo è disabilitato per sempre. Non riesco a inviare nuovamente dopo aver corretto i campi. (vedi il commento di bjan)

Quindi ho modificato lo script di vanstee in questo modo:

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

Qualche altro effetto collaterale da notare, o ha funzionato per te da applicare ovunque?
Ciaran Gallagher il

24

Il controllo dell'invio del modulo lato client può essere ottenuto in modo abbastanza elegante facendo in modo che il gestore onsubmit nasconda il pulsante di invio e lo sostituisca con un'animazione di caricamento. In questo modo l'utente ottiene un feedback visivo immediato nello stesso punto in cui è avvenuta la sua azione (il clic). Allo stesso tempo si impedisce che il modulo venga inviato un'altra volta.

Se invii il modulo tramite XHR, tieni presente che devi anche gestire gli errori di invio, ad esempio un timeout. Dovresti visualizzare di nuovo il pulsante di invio perché l'utente deve farlo inviare nuovamente il modulo.

In un'altra nota, llimllib solleva un punto molto valido. La convalida di tutti i moduli deve avvenire lato server. Ciò include più controlli di invio. Non fidarti mai del cliente! Questo non è solo un caso se javascript è disabilitato. È necessario tenere presente che tutto il codice lato client può essere modificato. È un po 'difficile da immaginare, ma html / javascript che parla con il tuo server non è necessariamente l'html / javascript che hai scritto.

Come suggerisce llimllib, genera il modulo con un identificatore univoco per quel modulo e mettilo in un campo di input nascosto. Memorizza quell'identificatore. Quando si ricevono i dati del modulo, elaborarli solo quando l'identificatore corrisponde. (Collegando anche l'identificatore alla sessione degli utenti e abbinarlo, anche per una maggiore sicurezza.) Dopo l'elaborazione dei dati, eliminare l'identificatore.

Ovviamente, di tanto in tanto, avresti bisogno di ripulire gli identificatori per i quali non è mai stato inviato alcun dato del modulo. Ma molto probabilmente il tuo sito web utilizza già una sorta di meccanismo di "raccolta dei rifiuti".


15
<form onsubmit="if(submitted) return false; submitted = true; return true">

6
Usa <form onsubmit="return (typeof submitted == 'undefined') ? (submitted = true) : !submitted">, o scrivere var submitted = false;al punto giusto dello script, per evitare il seguente errore: Uncaught ReferenceError: submitted is not defined.
Tamás Bolvári

15

Ecco un modo semplice per farlo:

<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>

con la convalida non invadente di jQuery, lo script di blocco viene chiamato per primo e successivamente la convalida che non risulta affatto
inoltrata

8

Disattiva il pulsante di invio subito dopo un clic. Assicurati di gestire correttamente le convalide. Mantieni anche una pagina intermedia per tutte le operazioni di elaborazione o DB e quindi reindirizza alla pagina successiva. Ciò assicura che l'aggiornamento della seconda pagina non esegua un'altra elaborazione.


Sì, ottimo suggerimento Shoban, sono d'accordo. Dovrebbe essereform page ---submits to---> form_submission_script.php ---after saving, redirects to---> form_thankyou.html
Simon East

6

Hash l'ora corrente, renderlo un input nascosto nel modulo. Sul lato server, controlla l'hash di ogni invio del modulo; se hai già ricevuto quell'hash, allora hai un nuovo invio.

modifica: affidarsi a javascript non è una buona idea, quindi tutti potete continuare a votare quelle idee, ma alcuni utenti non lo avranno abilitato. La risposta corretta è non fidarsi dell'input dell'utente sul lato server.


Non sembra "troppo"? ;-)
Shoban

1
Sembra che impedirebbe a un utente di inviare il modulo più di una volta al secondo. Se invio il modulo al 2009-05-29 12:13:37, il server non mi consente di inviare un altro modulo con lo stesso hash, ma se ho fatto clic su Invia al 2009-05-29 12:13:38, sarebbe passato. Inoltre, la tua tecnica impedirebbe a 2 utenti diversi di inviare contemporaneamente due moduli diversi: uno di loro verrebbe espulso, anche se potrebbe essere il primo invio da parte sua.
Sarah Vessels,

2
@moneypenny la tua prima obiezione è falsa, l'hash sarebbe del momento in cui il modulo è stato inviato all'utente, non dell'ora in cui lo invia. Se sei veramente preoccupato per il secondo, hai molte opzioni. Aggiungi il loro ID di sessione alla stringa che hai cancellato e / o controlla tutti i campi del modulo per verificarne l'identità esatta; probabilmente due utenti non hanno inviato esattamente lo stesso modulo.
llimllib

@Shoban mi dispiace, non seguo quello che dici
llimllib

2
"Eccessivo" è negli occhi di chi guarda. Se è davvero necessario impedire l'invio di moduli duplicati, almeno una parte della soluzione deve essere lato server. "Non puoi fidarti degli utenti."
Ben Blank

5

È inoltre possibile visualizzare una barra di avanzamento o una casella di selezione per indicare che il modulo è in fase di elaborazione.


5

Usando JQuery puoi fare:

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

&

   $('input:submit').keypress( function(e) {
     if (e.which == 13) {
        this.disabled = true 
     } 
    }
   );

1
Cosa succede se il modulo viene inviato premendo INVIO in una casella di testo dopo che il pulsante è stato disabilitato?
ichiban

Disabilitare il pulsante in questo modo impedirà all'utente di premere INVIO quindi. Ma, giusto, è necessario associare una pressione di un tasto sull'input di invio
Boris Guéry,

Ciò impedisce al pulsante di inviare. Quindi, disabilitando la convalida lato server.
Marko Aleksić

@Marko, giusto, ma questo è l'OP richiesto, comunque usare un token impedirebbe al modulo di presentarsi due volte.
Boris Guéry

1
Quando ho provato questo tipo di tecnica, ho scoperto che il modulo non veniva inviato affatto (almeno non in Chrome 14), presumibilmente perché disabiliti il ​​pulsante prima che il browser avvii l'invio del modulo.
Simon East

4

So che hai taggato la tua domanda con "javascript", ma ecco una soluzione che non dipende affatto da javascript:

È un pattern di webapp denominato PRG , ed ecco un buon articolo che lo descrive


4

Puoi impedire più invii semplicemente con:

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;

});

Il problema con la tua risposta è che c'è una frazione di secondo tra il momento in cui l'utente fa clic e l'ora Workin =true;. Sono ancora possibili doppi invii, ma probabilmente meno.
inviato il

4

La risposta più semplice a questa domanda è: "A volte, quando la risposta è lenta, è possibile fare clic più volte sul pulsante di invio. Come evitare che ciò accada?"

Disabilita semplicemente il pulsante di invio del modulo, come sotto il codice.

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

Disattiverà il pulsante di invio, al primo clic per l'invio. Inoltre, se hai alcune regole di convalida, funzionerà bene. Spero che possa aiutare.


penso che ti manchi qualcosa per favore inserisci il tuo codice.
Imran Khan

3

Sul lato client , dovresti disabilitare il pulsante di invio una volta che il modulo è stato inviato con codice javascript come il metodo fornito da @vanstee e @chaos.

Ma c'è un problema per il ritardo di rete o la situazione disabilitata da javascript in cui non dovresti fare affidamento sul JS per evitare che ciò accada.

Quindi, sul lato server , dovresti controllare l'invio ripetuto dagli stessi client e omettere quello ripetuto che sembra un falso tentativo da parte dell'utente.


So che è stata data una risposta molto tempo fa, ma qualcuno può spiegare come il ritardo di rete potrebbe impedire la disabilitazione? Sto affrontando questo problema in questo momento e sono molto confuso su come un modulo è stato inviato due volte, anche se disabilito il pulsante. Non ho mai nemmeno pensato a JavaScript disabilitato. Non credo che questo sia il problema nel mio caso, ma è comunque una visione interessante.
davidatthepark

Stavo anche pensando di limitare il gestore dei clic.
davidatthepark

3

Puoi provare il plugin jquery in forma sicura .

$('#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

La soluzione più semplice ed elegante per me:

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>

Link per ulteriori informazioni ...


1

Usa questo codice nel tuo form.it gestirà più clic.

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

funzionerà di sicuro.


1

Ciò consente l'invio ogni 2 secondi. In caso di convalida frontale.

$(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

il modo migliore per impedire l'invio di più file è semplicemente passare l'ID del pulsante nel metodo.

    function DisableButton() {
        document.getElementById("btnPostJob").disabled = true;
    }
    window.onbeforeunload = DisableButton; 

0

Fare questo usando javascript è un po 'facile. Di seguito è riportato il codice che darà la funzionalità desiderata:

$('#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

La soluzione più semplice è quella di disabilitare il pulsante al clic, abilitarlo al termine dell'operazione. Per verificare una soluzione simile su jsfiddle:

[click here][1]

E puoi trovare qualche altra soluzione su questa risposta .


1
Sebbene un collegamento sia ottimo, fornire un contesto ai collegamenti , poiché una risposta dovrebbe effettivamente contenere una risposta. Tieni presente che essere poco più di un collegamento a un sito esterno è una possibile ragione del perché e come vengono eliminate alcune risposte? .
Jan

0

Questo funziona molto bene per me. Invia la farm e disabilita il pulsante e dopo 2 sec attiva il pulsante.

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

In ECMA6 Syntex

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

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

setTimeout(() => { submitBtn.removeAttribute('disabled') }, 4000);}

0

Solo per aggiungere alle possibili risposte senza bypassare la convalida dell'input del browser

$( document ).ready(function() {
    $('.btn-submit').on('click', function() {
        if(this.form.checkValidity()) {
            $(this).attr("disabled", "disabled");
            $(this).val("Submitting...");
            this.form.submit();
        }
    });
});

0

Un'alternativa a quanto proposto prima è:

jQuery('form').submit(function(){
     $(this).find(':submit').attr( 'disabled','disabled' );
     //the rest of your code
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.