Formun müşteri tarafından birden çok kez gönderilmesi nasıl engellenir?


96

Bazen yanıt yavaş olduğunda, gönder düğmesine birden çok kez tıklanabilir.

Bunun olmasını nasıl önleyebilirim?


4
Umarım soru başlığınıza "istemci tarafı" ifadesini koymanızın nedeni, istemcide yinelenen gönderimleri denemek ve önlemek için herhangi bir çözümün% 100 güvensiz olduğunun farkında olmanız ve her zaman sunucu tarafında doğrulama yapmanız gerektiğidir .
Paolo Bergantino

52
Paolo: Evet, tam veri güvenliğiyle ilgileniyorsanız, sunucu tarafında yapılmalıdır. Ancak bazen, yalnızca tek bir tıklama gerektiğinde, büyükannenin gönder düğmesini çift tıklamasını engellemek istersiniz. Bu durumlarda javascript mükemmeldir.
Simon East

1
Bunu yalnızca sunucu tarafında yapmak da% 100 güvenli değildir, çünkü ilk isteğinizin tamamlanması yeterince uzun sürebilir, bu nedenle ikincisi devam etmemesi gerektiğini bilir.
igorsantos07

CSRF saldırılarını önlemek için Çift Gönderimli Çerez Kalıbı birden fazla form gönderimini de engellemiyor mu?
Martin Thoma

Yanıtlar:


99

Zaten gönderildikten sonra formdaki gönderme olayını devre dışı bırakmak için göze çarpmayan javascript kullanın. İşte jQuery kullanan bir örnek.

DÜZENLEME: Gönder düğmesini tıklamadan form göndermeyle ilgili sorun düzeltildi. Teşekkürler ichiban.

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

4
Form bir metin kutusuna enter tuşuna basılarak gönderilirse ne olur?
ichiban

2
Hatta ihtiyacın var return truemı? Bence ilk gönderim bu olmadan çalışmalı.
Simon East

return trueİhmal edilirse ima edildiğine inanıyorum .
Derek

15
Bu çözümü göze batmayan doğrulama ve MVC ile denedim. İlk olarak JS çağrılır ve her zaman yanlış döndürülür ve ardından doğrulama çağrılır. Yani formumda bazı doğrulama hataları varsa form asla gönderilmez !!
bjan

6
gerçekten harika çalışıyor. Ayrıca gönder düğmesini devre dışı bırakmak ve kullanıcıya ipucu göstermek için gönder düğmesi metnini değiştirmek istiyorum. $(this).find("input[type='submit']").attr('disabled', 'disabled').val('submiting'); return true; });
Cam Song

43

Vanstee'nin çözümünü asp mvc 3 göze batmayan doğrulama ile birlikte denedim ve istemci doğrulaması başarısız olursa, kod hala çalışıyor ve form gönderme tamamen devre dışı bırakılıyor. Alanları düzelttikten sonra yeniden gönderemiyorum. (bjan'ın yorumuna bakın)

Ben de vanstee'nin senaryosunu şu şekilde değiştirdim:

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

Dikkat edilmesi gereken başka yan etkiler var mı, yoksa bu her yere uygulamanızı sağladı mı?
Ciaran Gallagher

24

İstemci tarafı form gönderme kontrolü, onsubmit işleyicisinin gönder düğmesini gizlemesi ve onu bir yükleme animasyonuyla değiştirmesiyle oldukça zarif bir şekilde elde edilebilir. Bu şekilde kullanıcı, eyleminin (tıklama) gerçekleştiği noktada anında görsel geri bildirim alır. Aynı zamanda formun başka bir zaman gönderilmesini engellersiniz.

Formu XHR aracılığıyla gönderirseniz, zaman aşımı gibi gönderim hatalarını da işlemeniz gerektiğini unutmayın. Kullanıcının formu yeniden göndermesi gerektiğinden gönder düğmesini tekrar görüntülemeniz gerekir .

Bir başka kayda göre, llimllib çok geçerli bir noktayı ortaya koyuyor. Tüm form doğrulaması sunucu tarafında yapılmalıdır. Bu, birden çok gönderim kontrolünü içerir. Müşteriye asla güvenme! Bu sadece javascript devre dışı bırakıldığında bir durum değildir. Tüm istemci tarafı kodunun değiştirilebileceğini unutmamalısınız. Hayal etmesi biraz zor ama sunucunuzla konuşan html / javascript, yazdığınız html / javascript olmayabilir.

Llimllib'in önerdiği gibi, formu o form için benzersiz olan bir tanımlayıcıyla oluşturun ve gizli bir giriş alanına koyun. Bu tanımlayıcıyı saklayın. Form verilerini alırken, yalnızca tanımlayıcı eşleştiğinde işleyin. (Ayrıca ek güvenlik için tanımlayıcının kullanıcı oturumuna bağlanması ve bununla eşleştirilmesi.) Veri işlemeden sonra tanımlayıcıyı silin.

Elbette, ara sıra hiçbir form verisi gönderilmeyen tanımlayıcıları temizlemeniz gerekir. Ancak büyük olasılıkla web siteniz zaten bir tür "çöp toplama" mekanizması kullanıyor.


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

6
Kullanım <form onsubmit="return (typeof submitted == 'undefined') ? (submitted = true) : !submitted">veya yazma var submitted = false;senaryonuzun doğru noktada, aşağıdaki hatayı önlemek için: Uncaught ReferenceError: submitted is not defined.
Tamás Bolvári

15

İşte bunu yapmanın basit yolu:

<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 göze çarpmayan doğrulama ile, önce engelleme komut dosyası çağrılır ve ardından doğrulama hatası varsa hiçbir gönderim yapılmaz
bjan

8

Bir tıklamanın hemen ardından gönder düğmesini devre dışı bırakın. Doğrulamaları doğru şekilde yaptığınızdan emin olun. Ayrıca tüm işleme veya DB işlemleri için bir ara sayfa tutun ve ardından sonraki sayfaya yönlendirin. Bu, ikinci sayfayı yenilemenin başka bir işlem yapmamasını sağlar.


Evet, harika ipucu Shoban, katılıyorum. Olmalıform page ---submits to---> form_submission_script.php ---after saving, redirects to---> form_thankyou.html
Simon East

6

Geçerli saati karma haline getirin, formda gizli bir giriş yapın. Sunucu tarafında, her form gönderiminin karmasını kontrol edin; Bu hash'i zaten aldıysanız, tekrar gönderiminiz olur.

düzenleme: javascript'e güvenmek iyi bir fikir değildir, bu nedenle hepiniz bu fikirleri yükseltmeye devam edebilirsiniz, ancak bazı kullanıcılar bunu etkinleştirmeyecektir. Doğru cevap, sunucu tarafındaki kullanıcı girişine güvenilmemektir.


Bu "çok fazla" görünmüyor mu? ;-)
Shoban

1
Bu, bir kullanıcının formu saniyede bir defadan fazla göndermesini engelleyecek gibi görünüyor. Formu 2009-05-29 12:13:37 tarihinde gönderirsem, sunucu aynı hash ile başka bir form göndermeme izin vermez, ancak 2009-05-29 12:13:38'de Gönder'i tıklarsam, geçerdi. Ayrıca, tekniğiniz 2 farklı kullanıcının aynı anda iki farklı form göndermesini engelleyecektir: bunlardan biri, muhtemelen kendisinden ilk sunum olsa bile, atılacaktı.
Sarah Vessels

2
@moneypenny ilk itirazınız yanlış, hash, formun kullanıcıya gönderildiği zaman değil, gönderildiği zaman olacaktır. İkincisi için gerçekten endişeleniyorsanız, birçok seçeneğiniz var. Oturum kimliklerini hash ettiğiniz dizeye ekleyin ve / veya formun tüm alanlarını tam olarak aynılık için kontrol edin; iki kullanıcı muhtemelen tam olarak aynı formu göndermedi.
llimllib

@Shoban Üzgünüm, söylediklerinizi takip etmiyorum
llimllib

2
"Aşırı", bakanın gözündedir. Eğer varsa gerçekten çözümün az kısmında, yinelenen form gönderimleri önlemek için gereken sunucu tarafında olmak zorundadır. "Kullanıcılara güvenemezsiniz."
Ben Blank

5

Formun işlendiğini belirtmek için bir ilerleme çubuğu veya değer değiştirici de görüntüleyebilirsiniz.


5

JQuery kullanarak şunları yapabilirsiniz:

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

&

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

1
Ya form, düğme devre dışı bırakıldıktan sonra bir metin kutusunda ENTER tuşuna basılarak gönderilirse?
ichiban

Düğmeyi bu şekilde devre dışı bırakmak, kullanıcının daha sonra ENTER'a basmasını önleyecektir. Ancak, doğru, gönderme girdisine bir tuşa basılması gerekiyor
Boris Guéry,

Bu, düğmenin gönderilmesini engeller. Bu nedenle, sunucu tarafı doğrulamasını devre dışı bırakmak.
Marko Aleksić

@Marko, doğru, ama bu OP istendi, zaten bir jeton kullanmak formun iki kez gönderilmesini engelleyecektir.
Boris Guéry

1
Bu tür bir tekniği denediğimde, muhtemelen tarayıcı form göndermeye başlamadan önce düğmeyi devre dışı bıraktığınız için formun hiç gönderilmediğini fark ettim (en azından Chrome 14'te değil).
Simon East

4

Sorunuzu 'javascript' ile etiketlediğinizi biliyorum ama işte javascript'e hiç bağlı olmayan bir çözüm:

PRG adlı bir web uygulaması kalıbı ve işte onu açıklayan iyi bir makale


4

Birden fazla gönderimi basitçe şu şekilde engelleyebilirsiniz:

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;

});

Cevabınızla ilgili sorun, kullanıcının tıkladığı zaman ile zaman arasında bir saniye olmasıdır Workin =true;. Çift başvurular hala mümkündür, ancak daha az olasıdır.
sent1nel

4

Bu soruya verilen en basit cevap: "Bazen yanıt yavaş olduğunda gönder düğmesine birden çok kez tıklanabilir. Bunun olmasını nasıl önleyebilirim?"

Aşağıdaki kod gibi form gönderme düğmesini devre dışı bırakmanız yeterlidir.

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

Göndermek için ilk tıklamada gönder düğmesini devre dışı bırakacaktır. Ayrıca bazı doğrulama kurallarınız varsa, o zaman iyi çalışacaktır. Umarım yardımcı olur.


sanırım eksik bir şey var lütfen kodunuzu gönderin.
İmran Khan

3

İstemci tarafında , @vanstee ve @chaos tarafından sağlanan yöntem gibi javascript kodu ile form gönderildikten sonra gönder düğmesini devre dışı bırakmalısınız.

Ancak, bunun olmasını önlemek için JS'ye güvenmemeniz gereken ağ gecikmesi veya javascript devre dışı durumuyla ilgili bir sorun var.

Bu nedenle, sunucu tarafında , aynı istemcilerden tekrarlanan gönderimi kontrol etmeli ve kullanıcıdan yanlış bir girişim gibi görünen tekrarlanan gönderimi atlamalısınız.


Bunun uzun zaman önce yanıtlandığını biliyorum, ancak biri ağ gecikmesinin devre dışı bırakmayı nasıl önleyebileceğini açıklayabilir mi? Şu anda bu sorunla uğraşıyorum ve düğmeyi devre dışı bıraksam da bir formun nasıl iki kez gönderildiği konusunda kafam çok karışık. JavaScript'in devre dışı bırakıldığını hiç düşünmedim. Benim durumumdaki sorunun bu olduğunu sanmıyorum, ancak yine de ilginç bir fikir.
davidatthepark

Ayrıca tıklama işleyicisini de azaltmayı düşünüyordum.
davidatthepark

Aynı istemciden gönderim yaparsanız sunucu tarafını nasıl kontrol edersiniz? Kullanıcı IP adresine göre mi? Öyleyse, daha önce gönderilmiş bir girişten sunucu tarafındaki IP adresini nereye "kaydedersiniz"? (bu bağlam gerekliyse düğümü kullanıyorum)
user1063287

3

Safeform jquery eklentisini deneyebilirsiniz .

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

Benim için en basit ve zarif çözüm:

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>

Daha fazlası için bağlantı ...


1

Bu kodu formunuzda kullanın. Birden çok tıklama işleyecektir.

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

kesinlikle işe yarayacak.


1

Bu, her 2 saniyede bir gönderime izin verir. Ön doğrulama durumunda.

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

Birden fazla kişinin gönderilmesini önlemenin en iyi yolu, bu yöntemdeki düğme kimliğini iletmektir.

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

0

Bunu javascript kullanarak yapmak biraz kolaydır. İstenilen işlevselliği sağlayacak kod aşağıdadır:

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

En basit çözüm, tıklamadaki düğmeyi devre dışı bırakmak, işlem tamamlandıktan sonra etkinleştirmektir. Jsfiddle'da benzer çözümü kontrol etmek için:

[click here][1]

Ve bu cevapla ilgili başka bir çözüm bulabilirsiniz .


1
Bir bağlantı harika olsa da, lütfen bağlantılarınızın bağlamını sağlayın , çünkü bir cevap aslında bir cevap içermelidir. Harici bir siteye bir bağlantıdan ancak biraz daha fazlası olmanın , bazı yanıtların neden ve nasıl silineceği konusunda olası bir neden olduğunu unutmayın .
Jan

0

Bu benim için çok iyi çalışıyor. Çiftliği gönderin ve düğmeyi devre dışı bırakın ve 2 saniye sonra düğmeyi etkinleştirin.

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

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

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

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

0

Tarayıcı giriş doğrulamasını atlamadan olası yanıtlara eklemek için

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

0

Daha önce önerilenlere bir alternatif şudur:

jQuery('form').submit(function(){
     $(this).find(':submit').attr( 'disabled','disabled' );
     //the rest of your code
});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.