Làm cách nào để ngăn biểu mẫu gửi nhiều lần từ phía khách hàng?


96

Đôi khi khi phản hồi chậm, người ta có thể nhấp vào nút gửi nhiều lần.

Làm thế nào để ngăn chặn điều này xảy ra?


4
Tôi hy vọng lý do bạn đặt "phía máy khách" trên tiêu đề câu hỏi của mình là vì bạn nhận thức được rằng bất kỳ giải pháp nào trên máy khách để thử và tránh gửi bản dupe đều không an toàn 100% và bạn nên luôn xác thực ở phía máy chủ.
Paolo Bergantino

51
Paolo: Có, nếu bạn quan tâm đến bảo mật dữ liệu hoàn chỉnh, nó nên được thực hiện ở phía máy chủ. Nhưng đôi khi bạn chỉ muốn ngăn bà nội nhấp đúp vào nút gửi khi nó chỉ cần một cú nhấp chuột. Trong những trường hợp này, javascript hoàn toàn ổn.
Simon East,

1
Chỉ thực hiện nó ở phía máy chủ cũng không an toàn 100%, vì yêu cầu đầu tiên của bạn có thể mất đủ thời gian để hoàn thành nên yêu cầu thứ hai sẽ biết rằng nó không nên tiếp tục.
igorsantos07

Không phải Mẫu cookie gửi hai lần để ngăn các cuộc tấn công CSRF cũng ngăn việc gửi biểu mẫu nhiều lần sao?
Martin Thoma

Câu trả lời:


99

Sử dụng javascript không phô trương để vô hiệu hóa sự kiện gửi trên biểu mẫu sau khi nó đã được gửi. Đây là một ví dụ sử dụng jQuery.

CHỈNH SỬA: Đã khắc phục sự cố gửi biểu mẫu mà không nhấp vào nút gửi. Cảm ơn, ichiban.

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

4
Điều gì sẽ xảy ra nếu biểu mẫu được gửi bằng cách nhấn enter trong hộp văn bản?
ichiban

2
Bạn thậm chí cần return true? Tôi nghĩ rằng lần nộp ban đầu sẽ hoạt động mà không có điều đó.
Simon East

Tôi tin rằng return truenó được ngụ ý nếu bỏ qua.
Derek

15
Tôi đã thử giải pháp này với xác nhận & MVC không phô trương. JS được gọi đầu tiên luôn trả về false và sau đó xác nhận được gọi. Vì vậy, nếu biểu mẫu của tôi có một số lỗi xác thực, biểu mẫu sẽ không bao giờ được gửi !!
bjan

6
hoạt động thực sự tuyệt vời. tôi cũng muốn tắt nút gửi và thay thế văn bản nút gửi để hiển thị gợi ý người dùng. $(this).find("input[type='submit']").attr('disabled', 'disabled').val('submiting'); return true; });
Cam Song

42

Tôi đã thử giải pháp của vanstee cùng với xác thực không phô trương asp mvc 3 và nếu xác thực ứng dụng không thành công, mã vẫn chạy và gửi biểu mẫu bị vô hiệu hóa. Tôi không thể gửi lại sau khi sửa các trường. (xem bình luận của bjan)

Vì vậy, tôi đã sửa đổi tập lệnh của vanstee như thế này:

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

Có bất kỳ tác dụng phụ nào khác cần lưu ý, hoặc điều này đã làm cho bạn áp dụng ở mọi nơi?
Ciaran Gallagher

24

Việc kiểm soát gửi biểu mẫu phía máy khách có thể đạt được khá thanh lịch bằng cách để trình xử lý gửi kèm ẩn nút gửi và thay thế nó bằng một hoạt ảnh đang tải. Bằng cách đó, người dùng nhận được phản hồi trực quan ngay lập tức ở cùng một vị trí mà hành động của họ (nhấp chuột) đã xảy ra. Đồng thời, bạn ngăn không cho biểu mẫu được gửi vào lần khác.

Nếu bạn gửi biểu mẫu qua XHR, hãy nhớ rằng bạn cũng phải xử lý các lỗi gửi, ví dụ như thời gian chờ. Bạn sẽ phải hiển thị lại nút gửi vì người dùng cần gửi lại biểu mẫu.

Một lưu ý khác, llimllib đưa ra một điểm rất hợp lệ. Tất cả xác nhận biểu mẫu phải xảy ra phía máy chủ. Điều này bao gồm nhiều lần kiểm tra gửi. Đừng bao giờ tin tưởng khách hàng! Đây không chỉ là trường hợp nếu javascript bị tắt. Bạn phải ghi nhớ rằng tất cả mã phía máy khách đều có thể được sửa đổi. Hơi khó tưởng tượng nhưng html / javascript nói chuyện với máy chủ của bạn không nhất thiết phải là html / javascript bạn đã viết.

Như llimllib gợi ý, hãy tạo biểu mẫu với một số nhận dạng duy nhất cho biểu mẫu đó và đặt nó vào trường nhập ẩn. Lưu trữ mã định danh đó. Khi nhận dữ liệu biểu mẫu, chỉ xử lý nó khi số nhận dạng khớp. (Cũng liên kết số nhận dạng với phiên người dùng và đối sánh với phiên đó để tăng cường bảo mật.) Sau khi xử lý dữ liệu, hãy xóa số nhận dạng.

Tất nhiên, thỉnh thoảng, bạn cần phải xóa các mã định danh mà không bao giờ có bất kỳ dữ liệu biểu mẫu nào được gửi. Nhưng hầu hết có lẽ trang web của bạn đã sử dụng một số loại cơ chế "thu gom rác".


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

6
Sử dụng <form onsubmit="return (typeof submitted == 'undefined') ? (submitted = true) : !submitted">, hoặc ghi var submitted = false;tại điểm bên phải của kịch bản của bạn, để tránh các lỗi sau: Uncaught ReferenceError: submitted is not defined.
Tamás Bolvári

15

Đây là cách đơn giản để làm điều đó:

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

với jQuery xác nhận không phô trương, kịch bản chặn được gọi đầu tiên và xác nhận tiếp theo mà kết quả không nộp hồ sơ ở tất cả nếu có lỗi xác nhận
bjan

8

Tắt nút gửi ngay sau một cú nhấp chuột. Đảm bảo rằng bạn xử lý xác thực đúng cách. Đồng thời giữ một trang trung gian cho tất cả các hoạt động xử lý hoặc DB và sau đó chuyển hướng đến trang tiếp theo. Nó đảm bảo rằng Làm mới trang thứ hai không thực hiện một quá trình xử lý nào khác.


Vâng, mẹo tuyệt vời Shoban, tôi đồng ý. Nên làform page ---submits to---> form_submission_script.php ---after saving, redirects to---> form_thankyou.html
Simon East

6

Băm thời gian hiện tại, biến nó thành đầu vào ẩn trên biểu mẫu. Ở phía máy chủ, hãy kiểm tra hàm băm của mỗi lần gửi biểu mẫu; nếu bạn đã nhận được mã băm đó thì bạn sẽ phải gửi lại.

chỉnh sửa: dựa vào javascript không phải là một ý tưởng hay, vì vậy tất cả các bạn có thể tiếp tục ủng hộ những ý tưởng đó nhưng một số người dùng sẽ không bật nó. Câu trả lời đúng là không tin tưởng đầu vào của người dùng ở phía máy chủ.


Cái này trông có "Quá nhiều" không? ;-)
Shoban

1
Điều đó có vẻ như nó sẽ ngăn người dùng gửi biểu mẫu nhiều hơn một lần mỗi giây. Nếu tôi gửi biểu mẫu vào lúc 2009-05-29 12:13:37 thì máy chủ sẽ không cho phép tôi gửi biểu mẫu khác có cùng hàm băm đó, nhưng nếu tôi nhấp vào Gửi lúc 2009-05-29 12:13:38, nó sẽ đi qua. Ngoài ra, kỹ thuật của bạn sẽ ngăn 2 người dùng khác nhau gửi đồng thời hai biểu mẫu khác nhau: một trong số họ sẽ bị loại bỏ, mặc dù đó có thể là lần gửi đầu tiên từ anh ta.
Sarah tàu

2
@moneypenny phản đối đầu tiên của bạn là sai, giá trị băm sẽ là thời gian biểu mẫu được gửi đến người dùng, không phải thời gian họ gửi. Nếu bạn thực sự lo lắng về điều thứ hai, bạn có rất nhiều lựa chọn. Thêm ID phiên của họ vào chuỗi bạn băm và / hoặc kiểm tra tất cả các trường của biểu mẫu xem có giống hệt nhau không; hai người dùng có thể không gửi chính xác cùng một biểu mẫu.
llimllib

@Shoban Tôi xin lỗi, tôi không làm theo những gì bạn đang nói
llimllib

2
"Quá đáng" là trong mắt của người xử lý. Nếu bạn thực sự cần ngăn chặn việc gửi biểu mẫu trùng lặp, ít nhất một phần của giải pháp phải là phía máy chủ. "Bạn không thể tin tưởng người dùng."
Ben Blank

5

Bạn cũng có thể hiển thị một thanh tiến trình hoặc một con quay để cho biết rằng biểu mẫu đang được xử lý.


5

Sử dụng JQuery bạn có thể làm:

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

&

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

1
Điều gì sẽ xảy ra nếu biểu mẫu được gửi bằng cách nhấn ENTER trong hộp văn bản sau khi nút bị tắt?
ichiban

Việc tắt nút như thế này sẽ ngăn người dùng nhấn ENTER sau đó. Tuy nhiên, đúng nó cần phải liên kết một lần nhấn phím trên đầu vào gửi
Boris Guéry

Điều này ngăn nút gửi. Do đó, vô hiệu hóa xác thực phía máy chủ.
Marko Aleksić

@Marko, đúng, nhưng đó là OP yêu cầu, dù sao thì việc sử dụng mã thông báo sẽ ngăn biểu mẫu gửi hai lần.
Boris Guéry

1
Khi tôi thử loại kỹ thuật này, tôi thấy rằng biểu mẫu sẽ hoàn toàn không gửi (ít nhất là không phải trong Chrome 14), có lẽ vì bạn tắt nút trước khi trình duyệt bắt đầu gửi biểu mẫu.
Simon East,

4

Tôi biết bạn đã gắn thẻ câu hỏi của mình bằng 'javascript' nhưng đây là một giải pháp hoàn toàn không phụ thuộc vào javascript:

Đó là một mẫu ứng dụng web có tên PRG và đây là một bài viết hay mô tả nó


4

Bạn có thể ngăn nhiều lần gửi đơn giản bằng:

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;

});

Vấn đề với câu trả lời của bạn là có một khoảng thời gian ngắn giữa thời gian người dùng nhấp chuột và thời gian Workin =true;. Vẫn có thể gửi hai lần, nhưng ít khả năng hơn.
sent1nel

4

Câu trả lời đơn giản nhất cho câu hỏi này như được hỏi: "Đôi khi khi phản hồi chậm, người ta có thể nhấp vào nút gửi nhiều lần. Làm thế nào để ngăn điều này xảy ra?"

Chỉ cần vô hiệu hóa nút gửi biểu mẫu, như mã bên dưới.

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

Nó sẽ vô hiệu hóa nút gửi, trong lần nhấp đầu tiên để gửi. Ngoài ra, nếu bạn có một số quy tắc xác thực, thì nó sẽ hoạt động tốt. Hy vọng nó sẽ giúp ích.


Tôi nghĩ rằng bạn đang thiếu một cái gì đó, vui lòng đăng mã của bạn.
Imran Khan

3

Về phía khách hàng , bạn nên tắt nút gửi khi biểu mẫu được gửi bằng mã javascript giống như phương pháp được cung cấp bởi @vanstee và @chaos.

Nhưng có một vấn đề đối với độ trễ mạng hoặc tình huống bị vô hiệu hóa javascript mà bạn không nên dựa vào JS để ngăn điều này xảy ra.

Vì vậy, ở phía máy chủ , bạn nên kiểm tra lần gửi lặp lại từ các máy khách giống nhau và bỏ qua lần gửi lặp lại có vẻ là một nỗ lực sai từ người dùng.


Tôi biết điều này đã được trả lời từ lâu nhưng ai đó có thể giải thích cách mạng lag có thể ngăn chặn việc vô hiệu hóa không? Tôi đang giải quyết vấn đề này ngay bây giờ và tôi rất bối rối về cách một biểu mẫu được gửi hai lần mặc dù tôi đã tắt nút. Tôi thậm chí chưa bao giờ nghĩ về việc JavaScript bị tắt. Tôi không nghĩ đó là vấn đề trong trường hợp của tôi, nhưng dù sao thì đó cũng là một cái nhìn sâu sắc thú vị.
davidatthepark

Tôi cũng đang xem xét việc điều chỉnh trình xử lý nhấp chuột.
davidatthepark 19/08 '19

3

Bạn có thể thử plugin 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

Giải pháp đơn giản và thanh lịch nhất cho tôi:

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>

Liên kết để biết thêm ...


1

Sử dụng mã này trong biểu mẫu của bạn. Nó sẽ xử lý nhiều lần nhấp.

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

nó sẽ hoạt động chắc chắn.


1

Điều này cho phép gửi 2 giây một lần. Trong trường hợp xác nhận trước.

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

cách tốt nhất để ngăn nhiều người gửi là điều này chỉ cần chuyển id nút trong phương thức.

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

0

Để làm điều này bằng cách sử dụng javascript hơi dễ dàng. Sau đây là mã sẽ cung cấp chức năng mong muốn:

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

Hầu hết các giải pháp đơn giản là vô hiệu hóa nút khi nhấp, bật nó sau khi hoạt động hoàn tất. Để kiểm tra giải pháp tương tự trên jsfiddle:

[click here][1]

Và bạn có thể tìm thấy một số giải pháp khác trên câu trả lời này .


1
Mặc dù một liên kết rất tuyệt, nhưng hãy cung cấp ngữ cảnh cho (các) liên kết của bạn , vì một câu trả lời thực sự phải chứa một câu trả lời. Hãy lưu ý rằng chỉ có nhiều hơn một liên kết đến một trang web bên ngoài là một lý do có thể xảy ra là Tại sao và làm thế nào một số câu trả lời bị xóa? .
Ngày

0

Điều này làm việc rất tốt cho tôi. Nó gửi trang trại và làm cho nút vô hiệu hóa và sau 2 giây kích hoạt nút.

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

Trong ECMA6 Syntex

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

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

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

0

Chỉ để thêm vào các câu trả lời có thể mà không bỏ qua xác thực đầu vào của trình duyệt

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

0

Một thay thế cho những gì đã được đề xuất trước đó là:

jQuery('form').submit(function(){
     $(this).find(':submit').attr( 'disabled','disabled' );
     //the rest of your code
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.