zoukankan      html  css  js  c++  java
  • 防止重复提交 仅提交一次的终极绝杀技

    防止重复提交,通用的思路,就是当用户点击提交按钮后,在浏览器中用JS将按钮disable掉,从而阻止用户继续点击该按钮,实现防止重复提交的目的。网上防止重复提交的文章已经不少了,为啥我还要写呢,显然我不是吃饱了撑的。。。

    最近一个客户,老抱怨每个月总有几条重复的业务数据;但创建该业务数据的页面,我们已经应用了常规的防重复提交技术,为啥还这样呢…… 
    1. 常规防重复提交 

    <asp:Button runat="server" ID="btnPostBack1" Text="按我1" UseSubmitBehavior="false" OnClientClick="this.disabled=true;this.form.submit();"/>

    这里需要注意的是: 
    (1). UseSubmitBehavior="false" :需要设置成false,这样生成了个的input的类型才是button;如果用默认的true,生成的input的类型为submit,postback到服务器端,将不会触发button的服务器端事件; 
    (2). Button不能有ValidationGroup属性,否则,postback到服务器端,将不会触发button的服务器端事件; 

    2. 当遇上Validator控件 
    如果页面上使用了Validator控件,继续使用上面1种的方法,我们会发现,Validator控件失效了。因为将button disable掉后,提交的时候将不再使用Validator控件进行校验。 
    针对此问题,一个解决方案,就是提交前手动校验一次。如果我们用IE Develop tool来跟踪提交的JS代码,我们会发现asp.net是在Page_ClientValidate函数中来完成Validator中设置的校验,所以下面手工调用一次该方法,如果校验失败,则不提交: 

    1: <script type="text/javascript"> 
    function disableButton(button) 

    if (typeof (Page_ClientValidate) == 'function' && Page_ClientValidate() == false) 

    return false; 

    button.disabled = true; 
    return true; 

    </script> 

    <div> 
    <asp:TextBox runat="server" ID="tbxInput1"></asp:TextBox> 
    <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="tbxInput1" 
    ValidationGroup="Group1" ErrorMessage="*"></asp:RequiredFieldValidator> 
    <asp:Button runat="server" ID="btnPostBack1" Text="按我1" UseSubmitBehavior="false" 
    OnClientClick="disableButton(this);" OnClick="btnPostBack_Click"> 
    </asp:Button> 
    </div> 

    说明:如果页面上有多个Validator控件,并且多个Button需要进行分组校验,则只需要设置Button的ValidationGroup即可。 
    上面的这个方法,貌似已经完美了;通常情况下,文章写到这里也该结束了,我们的系统也是这么使用的。但是……最近一个客户,老抱怨每个月总有几条重复的业务数据。。。 
    . 当用户的点击速度足够快…… 
    根据客户的反馈信息,我们查了下那几条重复的业务数据,发现同样的记录偶尔会出现两次,并且DB中记录的创建时间完全相等(精确到毫秒)。然后也让用户的演示了一下她日常的操作方式,发现她点鼠标相当的快;虽然没有重现问题,但我们也大致知道问题的可能原因了:当用户点击的速度足够快,浏览器还没有来得及将button禁用掉,用户又点击了第二次…… 
    为了重现问题,我们做了如下测试: 

    <script type="text/javascript"> 
    function disableButton(button) //, validateGroup) 

    if (typeof (Page_ClientValidate) == 'function' && Page_ClientValidate() == false) 

    return false; 

    button.disabled = true; 


    function doubleClick() 

    var button1 = document.getElementById('btnPostBack1'); 
    button1.onclick(); 
    button1.onclick(); //模拟重复点击2次 

    </script> 


    <div> 
    <asp:TextBox runat="server" ID="tbxInput1"></asp:TextBox> 
    <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="tbxInput1" 
    ValidationGroup="Group1" ErrorMessage="*"></asp:RequiredFieldValidator> 
    <asp:Button runat="server" ID="btnPostBack1" Text="按我1" UseSubmitBehavior="false" 
    ValidationGroup="Group1" OnClientClick="disableButton(this);" OnClick="btnPostBack_Click"> 
    </asp:Button> 
    </div> 
    <input type="button" onclick="doubleClick();" value="点击一次,模拟连续点击'按我1'两次" /> 

    然后页面后台代码如下: 

    public static int i = 0; 
    protected void btnPostBack_Click(object sender, EventArgs e) 

    Response.Write(((Button)sender).Text + " " + (++i).ToString());//将累加结果输出 

    每次页面PostBack时,全局变量+1,如果连续PostBack两次,则得到的是+2的累计。测试的结果:除了偶尔+1,大部分情况都是累加2……看来,如果用户点击鼠标的速度足够快,前面2中的办法还是无法杜绝重复提交,咋办呢??? 

    4. 终极绝杀技

    处理思路就是,用数组记录用户的点击时间,如果点击时间小于某个时间间隔(下面演示的1秒,即1000毫秒),则认为是重复提交,并取消当前点击事件,直接上代码了:

    <html xmlns="http://www.w3.org/1999/xhtml"> 
    <head runat="server"> 
    <script type="text/javascript"> 
    var date = new Array(); 
    function disableButton(button, validateGroup) 

    date.push(new Date()); 
    if (date.length > 1 
    && (date[date.length - 1].getTime() - date[date.length - 2].getTime() < 1000))//小于1秒则认为重复提交 

    event.cancelBubble = true; //测试时发现,如果直接单独设置cancelBubble、或者returnValue来取消事件,经常取消不了,依然存在重复提交的可能。因此只好用返回值来实现手工控制! 
    return false; 

    if (typeof (Page_ClientValidate) == 'function' 
    && ((validateGroup == undefined && Page_ClientValidate() == false) 
    || (validateGroup != undefined && Page_ClientValidate(validateGroup) == false))) 
    { //如果指定了ValidateGroup,则只验证改组;如果未指定,则验证全部验证控件 
    return false; 


    button.disabled = true; 
    return true; 


    function doubleClick() 

    var button1 = document.getElementById('btnPostBack1'); 
    button1.onclick(); 
    button1.onclick(); 

    </script> 
    </head> 
    <body> 
    <form id="form" runat="server"> 
    <div> 
    <asp:TextBox runat="server" ID="tbxInput1"></asp:TextBox> 
    <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="tbxInput1" 
    ValidationGroup="Group1" ErrorMessage="*"></asp:RequiredFieldValidator> 
    <asp:Button runat="server" ID="btnPostBack1" Text="按我1" UseSubmitBehavior="false" 
    ValidationGroup="Group1" OnClientClick="if(!disableButton(this, 'Group1')) return false;" OnClick="btnPostBack_Click"> 
    </asp:Button> 
    </div> 
    <div> 
    <asp:TextBox runat="server" ID="tbxInput2"></asp:TextBox> 
    <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="tbxInput2" 
    ValidationGroup="Group2" ErrorMessage="*"></asp:RequiredFieldValidator> 
    <asp:Button runat="server" ID="btnPostBack2" Text="按我2" UseSubmitBehavior="false" 
    OnClientClick="if(!disableButton(this)) return false;" OnClick="btnPostBack_Click"> 
    </asp:Button> 
    </div> 
    <input type="button" onclick="doubleClick();" value="点击一次,模拟连续点击'按我1'两次" /> 
    </form> 
    </body> 
    </html> 

    说明: 
    (1). 测试时发现,如果直接单独设置cancelBubble、或者returnValue来取消事件,经常取消不了,依然存在高频率的重复提交。因此只好用返回值来实现手工控制; 
    (2). disableButton接收一个validateGroup参数,如果指定了ValidateGroup,则只验证改组;如果未指定,则验证全部验证控件。

  • 相关阅读:
    hiveserver2 with kerberos authentication
    python Basic usage
    python Quicksort demo
    Python HeapSort
    mrunit for wordcount demo
    CCDH证书
    Hadoop question list
    Hadoop Yarn core concepts
    Hadoop Resource
    Hadoop could not find or load main class
  • 原文地址:https://www.cnblogs.com/sjqq/p/6428431.html
Copyright © 2011-2022 走看看