Bagaimana cara mencegah formulir dikirim beberapa kali dari sisi klien?

96

Terkadang saat responsnya lambat, seseorang mungkin mengklik tombol kirim beberapa kali.

Bagaimana cara mencegah hal ini terjadi?

Oh Tuhan
sumber
4
Saya harap alasan Anda meletakkan "sisi klien" pada judul pertanyaan Anda adalah karena Anda mengetahui bahwa solusi apa pun pada klien untuk mencoba dan menghindari pengiriman penipuan adalah 100% tidak aman dan Anda harus selalu melakukan validasi di sisi server.
Paolo Bergantino
51
Paolo: Ya, jika Anda tertarik dengan keamanan data lengkap, ini harus dilakukan di sisi server. Tetapi terkadang Anda hanya ingin mencegah nenek mengklik dua kali tombol kirim ketika hanya perlu satu klik. Dalam kasus ini, javascript baik-baik saja.
Simon East
1
Melakukannya hanya di sisi server juga tidak 100% aman, karena permintaan pertama Anda mungkin membutuhkan waktu cukup lama untuk diselesaikan sehingga permintaan kedua akan tahu bahwa permintaan tersebut tidak boleh dilanjutkan.
igorsantos07
Bukankah Pola Cookie Pengiriman Ganda untuk mencegah serangan CSRF juga mencegah pengiriman formulir mutliple?
Martin Thoma

Jawaban:

99

Gunakan javascript yang tidak mengganggu untuk menonaktifkan acara pengiriman di formulir setelah itu telah dikirim. Berikut ini contoh penggunaan jQuery.

EDIT: Memperbaiki masalah pengiriman formulir tanpa mengklik tombol kirim. Terima kasih, ichiban.

$("body").on("submit", "form", function() {
    $(this).submit(function() {
        return false;
    });
    return true;
});
Starx
sumber
4
Bagaimana jika formulir dikirimkan dengan menekan enter di kotak teks?
ichiban
2
Apakah Anda membutuhkannya return true? Saya pikir pengiriman awal harus bekerja tanpa itu.
Simon East
Saya yakin return truetersirat jika dihilangkan.
Derek
15
Saya mencoba solusi ini dengan validasi & MVC yang tidak mengganggu. JS dipanggil pertama yang selalu mengembalikan false dan kemudian validasi dipanggil. Jadi jika formulir saya memiliki beberapa kesalahan validasi, formulir tidak pernah dikirimkan !!
bjan
6
bekerja sangat bagus. Saya juga ingin menonaktifkan tombol kirim dan mengganti teks tombol kirim untuk menunjukkan petunjuk pengguna juga. $(this).find("input[type='submit']").attr('disabled', 'disabled').val('submiting'); return true; });
Cam Song
42

Saya mencoba solusi vanstee bersama dengan validasi tidak mengganggu asp mvc 3, dan jika validasi klien gagal, kode masih dijalankan, dan pengiriman formulir dinonaktifkan untuk selamanya. Saya tidak dapat mengirim ulang setelah mengoreksi bidang. (lihat komentar bjan)

Jadi saya memodifikasi skrip vanstee seperti ini:

$("form").submit(function () {
    if ($(this).valid()) {
        $(this).submit(function () {
            return false;
        });
        return true;
    }
    else {
        return false;
    }
});
m irina
sumber
Adakah efek samping lain yang perlu diperhatikan, atau apakah ini berhasil untuk Anda terapkan di mana-mana?
Ciaran Gallagher
24

Kontrol pengiriman formulir sisi klien dapat dicapai dengan cukup elegan dengan meminta penangan onsubmit menyembunyikan tombol kirim dan menggantinya dengan animasi pemuatan. Dengan cara itu, pengguna mendapatkan umpan balik visual langsung di tempat yang sama di mana tindakannya (klik) terjadi. Pada saat yang sama Anda mencegah formulir dikirimkan di lain waktu.

Jika Anda mengirimkan formulir melalui XHR, perlu diingat bahwa Anda juga harus menangani kesalahan pengiriman, misalnya waktu tunggu. Anda harus menampilkan tombol kirim lagi karena pengguna perlu mengirim ulang formulir.

Di catatan lain, llimllib menampilkan poin yang sangat valid. Semua validasi formulir harus dilakukan di sisi server. Ini termasuk beberapa pemeriksaan pengiriman. Jangan pernah mempercayai klien! Ini bukan hanya kasus jika javascript dinonaktifkan. Anda harus ingat bahwa semua kode sisi klien dapat dimodifikasi. Agak sulit untuk membayangkan tetapi html / javascript yang berbicara ke server Anda belum tentu html / javascript yang Anda tulis.

Seperti yang disarankan llimllib, buat formulir dengan pengenal yang unik untuk formulir itu dan letakkan di kolom input tersembunyi. Simpan pengenal itu. Saat menerima data formulir hanya memprosesnya saat pengenal cocok. (Juga menautkan pengenal ke sesi pengguna dan mencocokkannya, juga, untuk keamanan ekstra.) Setelah pemrosesan data, hapus pengenal tersebut.

Tentu saja, sesekali, Anda perlu membersihkan pengenal yang tidak pernah mengirimkan data formulir apa pun. Tetapi kemungkinan besar situs web Anda sudah menggunakan semacam mekanisme "pengumpulan sampah".

rampok
sumber
15
<form onsubmit="if(submitted) return false; submitted = true; return true">
kekacauan
sumber
6
Gunakan <form onsubmit="return (typeof submitted == 'undefined') ? (submitted = true) : !submitted">, atau menulis var submitted = false;pada titik yang tepat dari naskah Anda, untuk menghindari kesalahan berikut: Uncaught ReferenceError: submitted is not defined.
Tamás Bolvári
15

Berikut cara sederhana untuk melakukannya:

<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>
ichiban
sumber
dengan validasi jQuery yang tidak mengganggu, skrip pemblokiran dipanggil terlebih dahulu dan validasi berikutnya yang tidak menghasilkan pengiriman sama sekali jika ada kesalahan validasi
bjan
8

Nonaktifkan tombol kirim segera setelah klik. Pastikan Anda menangani validasi dengan benar. Juga pertahankan halaman perantara untuk semua pemrosesan atau operasi DB dan kemudian alihkan ke halaman berikutnya. Ini memastikan bahwa Refresh halaman kedua tidak melakukan pemrosesan lain.

Shoban
sumber
Ya, tip bagus Shoban, saya setuju. Seharusnyaform page ---submits to---> form_submission_script.php ---after saving, redirects to---> form_thankyou.html
Simon East
6

Hash waktu saat ini, jadikan sebagai masukan tersembunyi di formulir. Di sisi server, periksa hash dari setiap pengiriman formulir; jika Anda sudah menerima hash itu maka Anda mendapat pengajuan ulang.

edit: mengandalkan javascript bukanlah ide yang baik, jadi Anda semua dapat terus meningkatkan ide-ide tersebut tetapi beberapa pengguna tidak akan mengaktifkannya. Jawaban yang benar adalah tidak mempercayai input pengguna di sisi server.

llimllib.dll
sumber
Bukankah ini terlihat "Terlalu banyak"? ;-)
Shoban
1
Kedengarannya itu hanya akan membuat pengguna tidak mengirimkan formulir lebih dari sekali per detik. Jika saya mengirimkan formulir pada 2009-05-29 12:13:37, server tidak akan mengizinkan saya mengirimkan formulir lain dengan hash yang sama, tetapi jika saya mengklik Kirim pada 2009-05-29 12:13:38, itu akan berhasil. Selain itu, teknik Anda akan mencegah 2 pengguna berbeda mengirimkan dua bentuk berbeda secara bersamaan: salah satunya akan ditendang, meskipun itu mungkin pengiriman pertama darinya.
Sarah Vessels
2
@moneypenny keberatan pertama Anda salah, hashnya adalah saat formulir dikirim ke pengguna, bukan saat mereka mengirimkan. Jika Anda benar-benar khawatir tentang yang kedua, Anda punya banyak pilihan. Tambahkan ID sesi mereka ke string yang Anda hash, dan / atau periksa semua bidang formulir untuk kesamaan persis; dua pengguna mungkin tidak mengirimkan formulir yang persis sama.
llimllib
@Shoban Maaf, saya tidak mengikuti apa yang Anda katakan
llimllib
2
"Berlebihan" ada di mata yang melihatnya. Jika Anda benar - benar perlu mencegah pengiriman formulir duplikat, setidaknya sebagian dari solusi harus berada di sisi server. "Anda tidak bisa mempercayai pengguna."
Ben Blank
5

Anda juga dapat menampilkan bilah kemajuan atau pemutar untuk menunjukkan bahwa formulir sedang diproses.

Tony Borf
sumber
5

Menggunakan JQuery, Anda dapat melakukan:

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

&

   $('input:submit').keypress( function(e) {
     if (e.which == 13) {
        this.disabled = true 
     } 
    }
   );
Boris Guéry
sumber
1
Bagaimana jika formulir dikirimkan dengan menekan ENTER di kotak teks setelah tombol dinonaktifkan?
ichiban
Menonaktifkan tombol seperti ini akan mencegah pengguna untuk menekan ENTER kemudian. Tapi, benar itu perlu mengikat tombol pada masukan kirim
Boris Guéry
Ini mencegah tombol untuk mengirim. Karenanya, nonaktifkan validasi sisi server.
Marko Aleksić
@Marko, benar, tapi itu OP yang diminta, toh pake token akan mencegah formulir untuk dikirim dua kali.
Boris Guéry
1
Ketika saya mencoba teknik semacam ini, saya menemukan bahwa formulir tidak akan dikirim sama sekali (setidaknya tidak di Chrome 14), mungkin karena Anda menonaktifkan tombol sebelum browser memulai pengiriman formulir.
Simon East
4

Saya tahu Anda menandai pertanyaan Anda dengan 'javascript' tetapi berikut ini solusi yang sama sekali tidak bergantung pada javascript:

Ini adalah pola aplikasi web bernama PRG , dan inilah artikel bagus yang menjelaskannya

Pablo Fernandez
sumber
4

Anda dapat mencegah banyak pengiriman hanya dengan:

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;

});
Alfa
sumber
Masalah dengan jawaban Anda adalah bahwa ada waktu sepersekian detik antara waktu pengguna mengklik dan waktu Workin =true;. Pengiriman ganda masih dimungkinkan, tetapi kemungkinannya lebih sedikit.
sent1nel
4

Jawaban paling sederhana untuk pertanyaan ini seperti yang ditanyakan: "Kadang-kadang ketika responsnya lambat, seseorang mungkin mengklik tombol kirim beberapa kali. Bagaimana mencegah hal ini terjadi?"

Nonaktifkan saja tombol kirim formulir, seperti kode di bawah ini.

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

Ini akan menonaktifkan tombol kirim, pada klik pertama untuk mengirimkan. Juga jika Anda memiliki beberapa aturan validasi, maka itu akan berfungsi dengan baik. Semoga bisa membantu.

Imran Khan
sumber
saya pikir Anda melewatkan sesuatu, silakan kirim kode Anda.
Imran Khan
3

Di sisi klien , Anda harus menonaktifkan tombol kirim setelah formulir dikirimkan dengan kode javascript seperti metode yang disediakan oleh @vanstee dan @chaos.

Tetapi ada masalah untuk kelambatan jaringan atau situasi nonaktif javascript di mana Anda tidak boleh mengandalkan JS untuk mencegah hal ini terjadi.

Jadi, di sisi server , Anda harus memeriksa pengiriman berulang dari klien yang sama dan menghilangkan pengiriman berulang yang tampaknya merupakan upaya palsu dari pengguna.

steveyang.dll
sumber
Saya tahu ini telah dijawab sejak lama, tetapi dapatkah seseorang menjelaskan bagaimana kelambatan jaringan dapat mencegah penonaktifan? Saya sedang menangani masalah ini sekarang dan saya sangat bingung tentang bagaimana formulir dikirim dua kali meskipun saya menonaktifkan tombolnya. Saya bahkan tidak pernah berpikir tentang JavaScript dinonaktifkan. Saya tidak berpikir itu adalah masalah dalam kasus saya, tetapi ini adalah wawasan yang menarik.
davidatthepark
Saya juga mempertimbangkan untuk membatasi penangan klik.
davidatthepark
Bagaimana Anda memeriksa sisi server jika pengiriman dari klien yang sama? Menurut alamat IP pengguna? Jika demikian, di mana Anda akan "menyimpan" sisi server alamat IP dari entri yang dikirimkan sebelumnya? (Saya menggunakan node jika konteks itu diperlukan)
user1063287
3

Anda dapat mencoba plugin jquery safeform .

$('#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;
    }
})
Max Kamenkov
sumber
1

Solusi paling sederhana dan elegan untuk saya:

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>

Tautan untuk lebih ...

Solis
sumber
1

Gunakan kode ini di formulir Anda. Itu akan menangani beberapa klik.

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

itu pasti akan berhasil.

Bachas
sumber
1

Ini mengizinkan pengiriman setiap 2 detik. Dalam kasus validasi depan.

$(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;
    });
})
Aurel
sumber
0

cara terbaik untuk mencegah beberapa pengiriman adalah dengan meneruskan id tombol dalam metode.

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

Untuk melakukan ini menggunakan javascript agak mudah. Berikut adalah kode yang akan memberikan fungsionalitas yang diinginkan:

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

Rish
sumber
0

Solusi paling sederhana adalah menonaktifkan tombol saat diklik, aktifkan setelah operasi selesai. Untuk memeriksa solusi serupa di jsfiddle:

[click here][1]

Dan Anda dapat menemukan solusi lain untuk jawaban ini .

Kalyani
sumber
1
Meskipun tautan itu bagus, harap berikan konteks ke tautan Anda , karena jawaban seharusnya benar-benar berisi jawaban. Sadarilah bahwa hampir tidak lebih dari tautan ke situs eksternal adalah alasan yang mungkin untuk Mengapa dan bagaimana beberapa jawaban dihapus? .
Jan
0

Ini bekerja dengan sangat baik untuk saya. Ini mengirimkan pertanian dan membuat tombol nonaktifkan dan setelah 2 detik aktifkan tombol.

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

Dalam ECMA6 Syntex

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

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

setTimeout(() => { submitBtn.removeAttribute('disabled') }, 4000);}
Awais Jameel
sumber
0

Hanya untuk menambah kemungkinan jawaban tanpa melewati validasi input browser

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

Alternatif dari apa yang telah diusulkan sebelumnya adalah:

jQuery('form').submit(function(){
     $(this).find(':submit').attr( 'disabled','disabled' );
     //the rest of your code
});
Kisded Szabi - CodeRevolution
sumber