最近在网上查了好久,基本上都是 Html 按钮:<input id="btnSubmit" type="button" value="提交" language="javascript" onclick="return Button1_onclick()" />而在 .NET 开发中,服务端按钮的使用越来越频繁,很难用 JavaScript 等客户端脚本防止重复提交:<asp:Button ID="btnSubmit" runat="server" Text="提交" OnClick="btnSubmit_Click" />protected void btnSubmit_Click(object sender, EventArgs e)
{...}
防止重复提交的方法:1、在数据库中使记录不能完全相同。
缺点1:为了让最近插入的数据容易降序排列,通常使用 ID 字段为主键,并设置自动编号,这样就没有完全相同的记录了。
缺点2:插入之前先判断除 ID 字段外,是否有相同的记录,如果有,则不插入;这样每插入一条记录都需要多一步查询,大大的浪费服务器资源。2、设置一个Session,在 Page_Load 的(!IsPostBack) 条件中赋值“未单击”;在 btn_Click 事件中,先判断是否为“未单击”,如果是,则提交,然后将 Session 中的值设置为“已提交”。
缺点1:如果 已经单击了一次提交按钮,Session 值就变成“已提交”了,当客户端再次点击时,就会被 btn_Click 中的判断所拦截,拦截之后应当如何处理呢?
a.直接 return ,可以有效避免重复提交;但是这样就无法转向“提交成功,请等待自动跳转”页面了,用户也就不知道是否真的已经提交上去,同时也不能利用跳转页防后退了。
b.直接跳转到“提交成功,请等待自动跳转”页面,这样只要用户单击两次按钮,就会跳转到此页,给用户带来迷惑;
而且这种方法,有可能在第一次单击没有提交完成,就触发第二次单击,导致数据提交不上去,但是又显示“提交成功,请等待自动跳转”。
缺点2:如果用户打开此页面,无意中单击了一次提交按钮;用户并不知道,从而继续填写表单,当表单填写完成,再次单击提交按钮时,导致数据提交不上去。
可以使用验证控件禁止文本框为空,避免客户无意中就单击了按钮;但是如果一个页面存在多个按钮,就不能使用该控件了。
防重复提交问题是老问题,也是棘手问题,很多人都在寻找比较完善的解决方案。
请大家畅所欲言。

解决方案 »

  1.   

    这个是个普遍的问题我的做法是自己写个button控件,设置上js,成功解决这个问题
     public class Button : System.Web.UI.WebControls.Button
        {
            int second = 0;
            [Category("控制台"), Browsable(true), Bindable(false), Description("自动启用的时间")]
            public int Second
            {
                get
                {
                    return second;
                }
                set
                {
                    second = value;
                }
            }
            string format = "({0})";
            [Category("控制台"), Browsable(true), Bindable(false), Description("格式")]
            public string Format
            {
                get
                {
                    return format;
                }
                set
                {
                    format = value;
                }
            }
            string confirm = "";
            [Category("控制台"),DefaultValue(""), Browsable(true), Bindable(false), Description("确认按钮")]
            public string Confirm
            {
                get
                {
                    return confirm;
                }
                set
                {
                    confirm = value;
                }
            }
            protected override void Render(HtmlTextWriter writer)
            {
                this.UseSubmitBehavior = false;//使用客户端提交机制
                //this.OnClientClick = "this.disabled='disabled';";
                if (this.CausesValidation)
                {
                    this.CausesValidation = false;
                    this.OnClientClick += "if (typeof(Page_ClientValidate) == 'function') if(!Page_ClientValidate()){return false;}";
                }
                if (string.IsNullOrEmpty(Confirm))
                {
                    this.OnClientClick += "this.disabled='disabled';";
                }
                else
                {
                    this.OnClientClick += "if(!confirm('" + Confirm + "')){return false;}this.disabled='disabled';";//点击以后按钮灰色,防止多次点击
                }
                if (Second>0)
                {
                    this.Attributes["disabled"]="disabled";
                    this.Text = this.Text + string.Format(Format, Second);
                    string script = @"
                            var Button_I="+Second.ToString()+ @";
                            var Button_X;
                            var Button_Format='"+Format+ @"';
                            function ButtonRefresh()
                            {   
                                if(Button_I==0)
                                {
                                    document.getElementById('" + this.ClientID+ @"').disabled='';
                                    var temp=document.getElementById('" + this.ClientID + @"').value;
                                    temp=temp.replace(Button_Format.replace('{0}',Button_I),'');
                                    document.getElementById('" + this.ClientID + @"').value=temp;
                                    window.clearInterval(Button_X);
                              }
                                else
                                {
                                    document.getElementById('" + this.ClientID + @"').disabled='disabled';
                                    var temp=document.getElementById('" + this.ClientID + @"').value;
                                    temp=temp.replace(Button_Format.replace('{0}',Button_I),Button_Format.replace('{0}',Button_I=Button_I-1));
                                    document.getElementById('" + this.ClientID + @"').value=temp;
                                }  
                            }
                            function window.onload()
                            {
                                Button_X=window.setInterval('ButtonRefresh()',1000);
                            }
                        ";
                    this.Page.ClientScript.RegisterStartupScript(this.GetType(), "Button", script, true);
                }
                base.Render(writer);
            }
    }
      

  2.   

    点击一次后,设置 Enabled 属性为 false
      

  3.   


    解决方法一:  .Framework2.0中才有的button属性:<asp:button id="btnSubmit" onclick="btnSubmit_Click" runat="server"  OnClientClick="this.disabled=true;this.form.submit();" UseSubmitBehavior="False" />     解决重复提交:OnClientClick="this.disabled=true;this.form.submit();" UseSubmitBehavior="False"解决方法二:   this.btnSubmit.Attributes["onclick"] = this.GetPostBackEventReference(this.btnSubmit) + ";this.disabled=true;";     //防止重复提交
      

  4.   

    OnClientClick="this.disabled=true;this.form.submit();" UseSubmitBehavior="False"
    我试过,似乎不管用...
      

  5.   

    提交按钮用js来写出来,禁用js无法提交 也看不到按钮<noscript>
      

  6.   

    怎么设置按钮无效?
    在后台设置,网速慢,传不到客户端就被单击多次了;
    在前台设置,这种按钮又不行,需要js,而js又是在客户端的,安全性、可靠性都不让人放心。
      

  7.   

    用JS在客户端控制是比较理解的办法
    服务器端的控制,对于这种问题,有点大牛拉小车的感觉不过有些情况下,还是要用的我的做法是
    在录入页页,做一个随机数,存入Session同时存入隐藏的表单元素里
    提交后在服务器端检查,相同则放行,否则提示错误信息,然后立即清除session
      

  8.   

    既然用session,不如cookie或viewstate,少占资源
      

  9.   


    对,如果写在存储过程中,效率也会提高,而且只需调用一次;如果写在后台代码中,则需要访问多次数据库。
    但是写在存储过程中,灵活性差。
    比如数据库中的 表名 不确定时,就不能用存储过程,只能用后台代码来拼接SQL语句了。
      

  10.   


    请问有代码段吗?
    如果在 Load_Page 中生成随机数,它就会在单击提交按钮后 Click 事件之前 自动再执行一次 Load_Page ,Session 中的随机数就更改了啊。
      

  11.   


    one: function( type, data, fn ) {
    return this.each(function(){
    jQuery.event.add( this, type, function(event) {
    jQuery(this).unbind(event);
    return (fn || data).apply( this, arguments);
    }, fn && data);
    });
    }
    <script type="text/javascript">
        $(document).ready(function(){
        
        $("p").one("click",function(){
            alert($(this).text());//这里放你要处理的
        
        });
        });
        
        </script>
    $.one()
    使用JQurey中的one函数可以轻松实现该功能
      

  12.   

    对防止二次提交方法两种:
    1. 完全用js写。
    2. 前台js和后台代码并合成写。具体方法:js+ajax
    我用的是第二种。
      

  13.   

    单击之后在哪里清空呢?
    如果是VS里面的标准控件(非html控件),就很难用前台代码控制。
    如果在后台控制Textbox清空,就需要等服务器的清空回传到客户机,才能实现清空,网速慢的话还未等到回传回来就已经单击好几次了。
      

  14.   

    <asp:Button ID="btnSubmit" runat="server" Text="提交" OnClick="btnSubmit_Click" />protected void btnSubmit_Click(object sender, EventArgs e)
    {...}请问这种按钮如何使用 JS?
      

  15.   

    写个存储过程控制!前台弄个javascript判断下
      

  16.   


    public void page_load(Object obj,EventArgs e) 
    ...{ 
       btn.Attributes.Add("onclick","state=true;"); 
       StringBuilder sb=new StringBuilder(); 
       sb.Append("if (!state) return;"); 
       sb.Append("var button=document.getElementById('btn');"); 
       sb.Append("button.value=" Please Wait... ";"); 
       sb.Append("document.body.style.cursor='wait';"); 
       sb.Append("button.disabled=true;");    string strScript="<script>"; 
       strScript=strScript +"var state=false;";    //将函数绑定到页面的onbeforeunload事件: 
       strScript=strScript +"window.attachEvent('onbeforeunload',function(){" +sb.ToString()+ "});"; 
       strScript=strScript +"</"+"script>"; 
       Page.RegisterStartupScript("onbeforeunload",strScript); 
    } private void Submit_Click(Object sender, EventArgs e)
    ...{ 
       //模拟长时间的按钮处理 
       System.Threading.Thread.Sleep(2000); 
       Response.Write("<script>alert('bbbbbb!!');"+"</"+"script>"); } <asp:button id="btn" Text="Submit" OnClick="Submit_Click" runat="server"/>你可以直接参考我的文章看怎么解决的:http://blog.csdn.net/lfywy/archive/2008/05/23/2475372.aspx
      

  17.   

    btnSubmit控件里加属性 OnClientClick="this.style.display='none';"protected void btnSubmit_Click(object sender, EventArgs e)
    {
        btnSubmit.Visiable=false;或btnSubmit.Disable=true;
    }
      

  18.   

    验证码很绝,但每次都让用户输入验证码,很不方便,
    论坛提交帖子可以,因为帖子输入好多字才需要输入一次验证码,
    但web应用程序就不行了,容易引起反感。OnClientClick 好像管用,目前没有那么慢的网速条件,无法一试。
    <asp:Button ID="btnSubmit" runat="server" Text="累加" OnClientClick="this.disabled=true;this.form.submit();" UseSubmitBehavior="False" OnClick="btnSubmit_Click" /><br />
        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            lbl.Text = Convert.ToString(Convert.ToInt32(lbl.Text) + 1);
        }
      

  19.   

    引用楼主的话“ 而在 .NET 开发中,服务端按钮的使用越来越频繁,很难用 JavaScript 等客户端脚本防止重复提”
    这是错误的,客户端按钮可以通过return false禁止提交,那asp.net自带的控件按钮当然也可以。
    这是没有什么区别的,不知道楼主担心何在。
      

  20.   

    我使用的struts有办法防止,只需要在后台代码的开始处判断是否isTokenValid即可,处理完毕给它reset。
      

  21.   

    另外我还在页面上给button写js,把enable设置为false
      

  22.   


    是这样:一个表单页,一个防后退跳转页(上面写着“提交成功,自动返回”);
    表单提交成功后,会自动转至跳转页,然后自动跳回。
    如果用 return 禁止提交,就不能跳到跳转页显示“提交成功,自动返回”了,用户并不知道实际上已经提交成功了。
      

  23.   

    就整一开发结构的不合理
    ajax来写
    把后退按钮都给屏蔽了
      

  24.   

    csdn的做法好象是变成把button的enabled变为false.
      

  25.   

    这个是我网上找的一个类 可以防止刷新多次提交
    using System;
    using System.Collections.Generic;
    using System.Text;
    /**/
    /// <summary>
    /// 名称:SubmitOncePage 
    /// 父类:System.Web.UI.Page
    /// 描述:解决浏览器刷新造成的数据重复提交问题的page扩展类。
    /// 示例:    if (!this.IsRefreshed)
    ///            {
    ///                //具体代码
    ///            }
    ///    原创:丛兴滋(cncxz)    E-mail:[email protected]
    /// </summary>
    namespace SPA.Common
    {
        public class SubmitOncePage : System.Web.UI.Page
        {
            private string _strSessionKey;
            private string _hiddenfieldName;
            private string _strLastViewstate;
            public SubmitOncePage()
            {
                _hiddenfieldName = "__LastVIEWSTATE_SessionKey";
                _strSessionKey = System.Guid.NewGuid().ToString();
                _strLastViewstate = string.Empty;        }        public bool IsRefreshed
            {
                get
                {
                    string str1 = this.Request.Form["__VIEWSTATE"];
                    _strLastViewstate = str1;
                    string str2 = this.Session[GetSessinKey()] as string;
                    bool flag1 = (str1 != null) && (str2 != null) && (str1 == str2);
                    return flag1;
                }
            }        protected override void Render(System.Web.UI.HtmlTextWriter writer)
            {
                string str = GetSessinKey();
                this.Session[str] = _strLastViewstate;
                this.RegisterHiddenField(_hiddenfieldName, str);
                base.Render(writer);
            }
            private string GetSessinKey()
            {
                string str = this.Request.Form[_hiddenfieldName];
                return (str == null) ? _strSessionKey : str;
            }
        }}
    下面代码是调用上面的IsRefreshed属性  但是事先要继承 SubmitOncePage 类namespace SPA.Web
    {
    public partial class Default1 : SPA.Common.SubmitOncePage
    {
            protected void Page_Load(object sender, EventArgs e)
            {
            }
            protected void Button4_Click(object sender, EventArgs e)
            {
                int i = int.Parse(Label2.Text) + 1;
                Label2.Text = i.ToString();
                if (!this.IsRefreshed)
                {
                    WriteFile("a.txt", i.ToString());
                }
                WriteFile("b.txt", i.ToString());  
            
            }
    }
    }
    不知道是不是你要想的  如果不清楚可加我QQ38789461
      

  26.   

    上面那个Button4_Click方法是为了测试 a.txt 和b.txt 写入的数字有何不同 你建a.txt b.txt  2个文本 然后提交几次 然后刷新页面几次 看看有什么不同吧
      

  27.   

    如果禁用js……那你干脆,禁用IE算了,现在网页有多少是不用js的?
      

  28.   

    其实这种情况的存在, 主要原因是滥用自动编号的ID, 而且将其设置为表的唯一一个主键, 我的设计一般不建议用自动编号的ID, 即使使用ID(某些情况确实使用ID对编程技巧有帮助), 也要有其他可以设置为UniqueKey的字段.这样可以避免同一记录写入几次.
      

  29.   

    谢谢楼上启发。
    下面是我写的针对LinkButton防止重复提交:UploadFileSubmit.Attributes.Add("onclick", "return checkSubmitCount();");
    UploadFileSubmit.Attributes.Add("href", "javascript:" + "submitCount++;" + Page.ClientScript.GetPostBackEventReference(UploadFileSubmit, "Click"));System.Text.StringBuilder sb = new StringBuilder();
    sb.Append("<script>");
    sb.Append("var submitCount = 0;\n");
    sb.Append("function checkSubmitCount() {");
    sb.Append("    if(submitCount==0)");
    sb.Append("        return true;");
    sb.Append("    return false;");
    sb.Append("}");
    sb.Append("\n\n");
    sb.Append("</script>");
    Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "preventMultipleSubmit", sb.ToString());