【问题标题】:How to prevent form from submitting multiple times from client side?如何防止表单从客户端多次提交?
【发布时间】:2010-10-29 22:26:09
【问题描述】:

有时响应慢,可能会多次点击提交按钮。

如何防止这种情况发生?

【问题讨论】:

  • 我希望您在问题标题上加上“客户端”的原因是因为您知道客户端上尝试避免重复提交的任何解决方案都是 100% 不安全的,您应该始终 在服务器端进行验证。
  • Paolo:是的,如果您对完整的数据安全感兴趣,应该在服务器端完成。但有时你只是想阻止奶奶在只需要单击的情况下双击提交按钮。在这些情况下,javascript 非常好。
  • 只在服务器端执行也不是 100% 安全,因为您的第一个请求可能需要足够长的时间才能完成,因此第二个请求会知道它不应该继续。
  • 防止CSRF攻击的Double-Submit Cookie Pattern不也能防止多表单提交吗?

标签: javascript submit


【解决方案1】:

在表单已提交后,使用不显眼的 javascript 禁用表单上的提交事件。这是一个使用 jQuery 的示例。

编辑:修复了在不单击提交按钮的情况下提交表单的问题。谢谢,一番。

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

【讨论】:

  • 如果表单是通过在文本框中按回车提交的?
  • 你还需要return true吗?我认为没有那个,初始提交应该可以工作。
  • 我相信 return true 如果省略是隐含的。
  • 我用不显眼的验证和 MVC 尝试了这个解决方案。首先调用 JS,它总是返回 false,然后调用验证。所以如果我的表单有一些验证错误,表单永远不会被提交!
  • 真的很棒。我也喜欢禁用提交按钮并替换提交按钮文本以显示用户提示。 $(this).find("input[type='submit']").attr('disabled', 'disabled').val('submiting'); return true; });
【解决方案2】:

我尝试了vanstee's solution 和 asp mvc 3 不显眼的验证,如果客户端验证失败,代码仍然运行,并且表单提交被永久禁用。更正字段后我无法重新提交。 (见 bjan 的评论)

所以我修改了 vanstee 的脚本如下:

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

【讨论】:

  • 还有其他需要注意的副作用吗,或者这对你来说适用于任何地方?
【解决方案3】:

通过让 onsubmit 处理程序隐藏提交按钮并用加载动画替换它,可以非常优雅地实现客户端表单提交控制。这样,用户在他的动作(点击)发生的同一地点获得即时的视觉反馈。同时,您会阻止表单再次提交。

如果您通过 XHR 提交表单,请记住您还必须处理提交错误,例如超时。您必须再次显示提交按钮,因为用户需要重新提交表单。

另一方面,llimllib 提出了一个非常有效的观点。 所有表单验证必须在服务器端进行。这包括多次提交检查。 永远不要相信客户端! 这不仅是禁用 javascript 的情况。您必须记住,所有客户端代码都可以修改。有点难以想象,但与您的服务器对话的 html/javascript 不一定是您编写的 html/javascript。

正如 llimllib 建议的那样,生成具有该表单唯一标识符的表单并将其放在隐藏的输入字段中。存储该标识符。接收表单数据时,仅在标识符匹配时处理它。 (还将标识符链接到用户会话并与之匹配,以提高安全性。)数据处理后删除标识符。

当然,有时您需要清理从未提交过任何表单数据的标识符。但很可能您的网站已经采用了某种“垃圾收集”机制。

【讨论】:

    【解决方案4】:

    这里有一个简单的方法:

    <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 非侵入式验证,首先调用阻塞脚本,然后验证,如果出现验证错误,则根本不会提交
    【解决方案5】:
    <form onsubmit="if(submitted) return false; submitted = true; return true">
    

    【讨论】:

    • 使用&lt;form onsubmit="return (typeof submitted == 'undefined') ? (submitted = true) : !submitted"&gt;,或在脚本的右侧写上var submitted = false;,以避免出现以下错误:Uncaught ReferenceError: submitted is not defined
    【解决方案6】:

    对于这个问题的最简单的回答是:“有时响应速度很慢,可能会多次单击提交按钮。如何防止这种情况发生?”

    只需禁用表单提交按钮,如下面的代码。

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

    它会禁用提交按钮,在第一次点击提交。此外,如果您有一些验证规则,那么它会正常工作。希望它会有所帮助。

    【讨论】:

    • 我认为您遗漏了一些东西,请发布您的代码。
    • 这个答案美丽而完美。我不明白为什么它的票数很少?
    • onsubmit 函数稍作调整,这样您就不必对提交元素名称进行硬编码:this.querySelector('input[type=submit]').disabled = true; return true;
    【解决方案7】:

    创建一个唯一标识符(例如,您可以散列当前时间),并使其成为表单上的隐藏输入。在服务器端,检查每个表单提交的唯一标识符;如果您已经收到了该哈希,那么您已经收到了重复提交。用户重新提交的唯一方法是重新加载表单页面。

    编辑:依赖 javascript 不是一个好主意,所以你们都可以继续支持这些想法,但有些用户不会启用它。正确的答案是不信任服务器端的用户输入。

    【讨论】:

    • 这看起来是不是“太过分了”? ;-)
    • 听起来它只会阻止用户每秒提交表单超过一次。如果我在 2009-05-29 12:13:37 提交表单,那么服务器不会让我提交具有相同哈希的另一个表单,但是如果我在 2009-05-29 12:13:38 点击提交,它会通过。此外,您的技术将阻止 2 个不同的用户同时提交两个不同的表单:其中一个会被踢出,即使这可能是他的第一次提交。
    • @moneypenny 您的第一个反对意见是错误的,哈希将是表单发送给用户的时间,而不是他们提交的时间。如果你真的担心第二个,你有很多选择。将他们的会话 ID 添加到您散列的字符串中,和/或检查表单的所有字段是否完全相同;两个用户可能没有提交完全相同的表单。
    • “过分”在旁观者的眼中。如果您真的需要防止重复提交表单,那么至少部分解决方案必须是服务器端的。 “你不能信任用户。”
    • 大家似乎对这个解决方案中时间戳哈希的使用有误解。时间戳哈希的重点是获取唯一标识符,而不是时间。唯一的 id 标识了表单实例,它应该只提交一次。如果该 id 提交了两次,则将其标记为重复。如果用户想重新提交,他们必须重新加载表单。
    【解决方案8】:

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

    【讨论】:

    • 是的,很棒的小费 Shoban,我同意。应该是form page ---submits to---&gt; form_submission_script.php ---after saving, redirects to---&gt; form_thankyou.html
    【解决方案9】:

    您还可以显示进度条或微调器以指示表单正在处理。

    【讨论】:

      【解决方案10】:

      使用 JQuery 你可以做到:

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

      &

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

      【讨论】:

      • 如果在禁用按钮后在文本框中按 ENTER 提交表单怎么办?
      • 禁用这样的按钮将阻止用户按 ENTER 键。但是,它需要在提交输入上绑定一个按键
      • 这会阻止按钮提交。因此,禁用服务器端验证。
      • @Marko,对,但这是 OP 要求的,无论如何使用令牌会阻止表单提交两次。
      • 当我尝试这种技术时,我发现表单根本不会提交(至少在 Chrome 14 中不会),大概是因为您在浏览器开始提交表单之前禁用了按钮。
      【解决方案11】:

      我知道您用“javascript”标记了您的问题,但这里有一个完全不依赖于 javascript 的解决方案:

      这是一个名为 PRG 的 webapp 模式,这里有一个 good article 对其进行描述

      【讨论】:

        【解决方案12】:

        你可以简单地防止多次提交:

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

        【讨论】:

        • 你的回答的问题是用户点击的时间和Workin =true;的时间之间有一个瞬间。双重提交仍然是可能的,但可能性较小。
        【解决方案13】:

        在客户端,一旦使用 javascript 代码提交表单后,您应该禁用提交按钮,就像 @vanstee 和 @chaos 提供的方法一样。

        但是存在网络延迟或javascript禁用情况的问题,您不应该依赖JS来防止这种情况发生。

        因此,在服务器端,您应该检查来自相同客户端的重复提交,并忽略重复提交,这似乎是用户的错误尝试。

        【讨论】:

        • 我知道这个问题很久以前就已经回答过了,但是有人可以解释一下网络延迟是如何阻止禁用的吗?我现在正在处理这个问题,即使我禁用了按钮,我也对如何重复提交表单感到非常困惑。我什至从未想过禁用 JavaScript。我认为这不是我的问题,但它仍然是有趣的见解。
        • 我也在考虑限制点击处理程序。
        • 如果从同一个客户端提交,你将如何检查服务器端?通过用户IP地址?如果是这样,您将在哪里“保存”以前提交的条目中的 IP 地址服务器端? (如果需要该上下文,我正在使用节点)
        【解决方案14】:

        你可以试试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;
            }
        })
        

        【讨论】:

          【解决方案15】:

          对我来说最简单优雅的解决方案:

          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 for more...

          【讨论】:

            【解决方案16】:

            在您的表单中使用此代码。它将处理多次点击。

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

            它肯定会起作用。

            【讨论】:

              【解决方案17】:

              这允许每 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;
                  });
              })
              

              【讨论】:

                【解决方案18】:

                防止多次提交的最好方法是这样 只需在方法中传递按钮 id。

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

                【讨论】:

                  【解决方案19】:

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

                  【讨论】:

                    【解决方案20】:

                    最简单的解决方案是在单击时禁用按钮,在操作完成后启用它。要检查 jsfiddle 上的类似解决方案:

                    [click here][1]
                    

                    您可以在此answer 上找到其他解决方案。

                    【讨论】:

                    【解决方案21】:

                    这对我来说很好用。它提交农场并禁用按钮并在 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 语法中

                    function submitLimit() {
                    submitBtn = document.getElementById('submit');
                    
                    setTimeout(() => { submitBtn.setAttribute('disabled', 'disabled') }, 1);
                    
                    setTimeout(() => { submitBtn.removeAttribute('disabled') }, 4000);}
                    

                    【讨论】:

                      【解决方案22】:

                      只是在不绕过浏览器输入验证的情况下添加可能的答案

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

                      【讨论】:

                        【解决方案23】:

                        之前提出的替代方案是:

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

                        【讨论】:

                          【解决方案24】:
                          <h3>Form</h3>
                          <form action='' id='theform' >
                          <div class='row'>
                              <div class="form-group col-md-4">
                                      <label for="name">Name:</label>
                                      <input type='text' name='name' class='form-control'/>
                              </div>
                          </div>  
                          <div class='row'>
                              <div class="form-group col-md-4">
                                      <label for="email">Email:</label>
                                      <input type='text' name='email' class='form-control'/>
                              </div>
                          </div>  
                          <div class='row'>
                              <div class="form-group col-md-4">
                                   <input class='btn btn-primary pull-right' type="button" value="Submit" id='btnsubmit' />   
                              </div>
                          </div>
                          </form>
                          
                          
                          
                          <script>
                          
                              $(function()
                              {
                                $('#btnsubmit').on('click',function()
                                {
                                  $(this).val('Please wait ...')
                                    .attr('disabled','disabled');
                                  $('#theform').submit();
                                });
                                
                              });
                          
                          </script>
                          
                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 2013-05-24
                          • 1970-01-01
                          • 2014-06-13
                          • 2012-09-19
                          • 1970-01-01
                          • 2020-11-23
                          相关资源
                          最近更新 更多