如何防止表单从客户端多次提交?


96

有时,当响应缓慢时,人们可能会多次单击“提交”按钮。

如何防止这种情况发生?


4
我希望在问题标题上加上“客户端”的原因是因为您知道客户端上尝试避免重复提交的任何解决方案都是100%不安全的,因此您应该始终在服务器端进行验证。
Paolo Bergantino,

51
保罗:是的,如果您对完整的数据安全性感兴趣,应该在服务器端进行。但是有时您只想阻止奶奶在只需要单击时双击提交按钮。在这些情况下,javascript非常好。
西蒙东

1
仅在服务器端执行此操作也不是100%安全的,因为您的第一个请求可能要花很长时间才能完成,因此第二个请求会知道它不应继续进行。
igorsantos15年7

防止CSRF攻击的Double-Submit Cookie模式也不会阻止多形式提交吗?
Martin Thoma

Answers:


99

在提交事件后,请使用不吸引人的javascript禁用表单上的Submit事件。这是使用jQuery的示例。

编辑:修复了不单击提交按钮即可提交表单的问题。谢谢,一番

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

4
如果通过在文本框中按Enter提交表单怎么办?
一班

2
您甚至需要return true吗?我认为最初的提交应该可以做到这一点。
西蒙东

我相信,return true如果省略则暗含。
德里克(Derek)

15
我尝试了无干扰的验证和MVC解决方案。首先调用JS,它总是返回false,然后调用验证。因此,如果我的表单存在一些验证错误,则该表单将永远不会提交!
bjan 2012年

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
陶Bolvári

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非侵入式验证时,将首先调用阻止脚本,然后再调用验证,如果存在验证错误,则根本不提交任何内容
2012年

8

单击后立即禁用提交按钮。确保正确处理验证。同时为所有处理或数据库操作保留一个中间页面,然后重定向到下一页。这可以确保刷新第二页不会进行其他处理。


是的,很棒的技巧Shoban,我同意。应该是form page ---submits to---> form_submission_script.php ---after saving, redirects to---> form_thankyou.html
Simon East

6

散列当前时间,使其成为表单上的隐藏输入。在服务器端,检查每个表单提交的哈希;如果您已经收到该哈希,则需要重复提交。

编辑:依靠javascript不是一个好主意,因此所有人都可以继续支持那些主意,但是有些用户不会启用它。正确的答案是不信任服务器端的用户输入。


看起来不是“太多”吗?;-)
Shoban

1
听起来这只会使用户每秒提交一次以上的表单。如果我在2009-05-29 12:13:37提交表单,则服务器不会让我提交另一个具有相同哈希值的表单,但是如果我在2009-05-29 12:13:38单击了提交,它会通过。此外,您的技术还可以防止2个不同的用户同时提交两种不同的表单:即使可能是他的第一次提交,也会踢出其中的一种。
莎拉·弗赛尔斯

2
@moneypenny您的第一个异议是错误的,哈希将是表单发送给用户的时间,而不是用户提交的时间。如果您真的担心第二个,则有很多选择。将其会话ID添加到您哈希的字符串中,和/或检查表单中的所有字段是否完全相同;两个用户可能没有提交完全相同的表格。
llimllib

@Shoban对不起,我不遵守您的意思
llimllib

2
情人眼中“过多”。如果确实需要防止重复提交表单,则解决方案的至少一部分必须在服务器端。“你不能信任用户。”
本·布兰克


5

使用JQuery,您可以执行以下操作:

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

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

1
如果在禁用按钮后通过在文本框中按ENTER提交表单,该怎么办?
一番

禁用这样的按钮将阻止用户随后按ENTER。但是,对需要绑定一个按键上提交输入
鲍里斯·伽利湖

这样可以防止按钮提交。因此,禁用服务器端验证。
MarkoAleksić2011年

@Marko,对,但这是OP要求的,无论如何使用令牌将阻止表单提交两次。
鲍里斯·格里(BorisGuéry)2011年

1
当我尝试这种技术时,我发现表单根本不会提交(至少在Chrome 14中不提交),大概是因为在浏览器开始提交表单之前禁用了按钮。
西蒙·伊斯特


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;

});

您的答案的问题在于,用户点击的时间与time之间存在一秒钟的间隔Workin =true;。仍然可以进行两次提交,但提交的次数可能更少。
send1nel 2014年

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

如果来自同一客户端的提交,您将如何检查服务器端?通过用户IP地址?如果是这样,您将在哪里将IP地址从先前提交的条目“保存”到服务器端?(如果需要该上下文,我正在使用节点)
user1063287

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

防止多个文件提交的最好方法是,只需在方法中传递按钮ID。

    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

这对我来说很好。它提交服务器场并禁用按钮,并在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();
        }
    });
});

0

以前提出的替代方案是:

jQuery('form').submit(function(){
     $(this).find(':submit').attr( 'disabled','disabled' );
     //the rest of your code
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.