posts - 46, comments - 76, trackbacks - 5, articles - 1

【ASP.NET】防止ASP.NET按钮多次提交的办法

Posted on 2008-07-17 23:40 xujh 阅读(2161) 评论(25)  编辑 收藏 所属分类: ASP.NET
网上查了很多方法,都不太好使,不如自己写一个,思路就是把按钮按下时用Javascript在客户端把按钮下一次的onclick事件改为return false; 这样在服务器端页面重新送回客户端之前,再次点击按钮都不会Post到服务端。同时将按钮的style改为一行字的样子,光标也变成沙漏状。当服务端页面重新产生后Button又会回到初始状态。该方法对于F5刷新还不能防范,只是简单封闭了F5的按键,为了防止刷新时再次提交可以在页面返回前将一些TextBox控件清空,这样就可以判断如果该TextBox为空则不再进行后续操作(如写库)。 或是后台操作成功后跳转到另一个页面以防止恶意刷新。主要是考虑在企业内网使用,不是为了防黑客,所以不是非常严格。
 1<html xmlns="http://www.w3.org/1999/xhtml">
 2<head runat="server">
 3    <title>禁止多次提交网页测试</title>
 4    <style type="text/css">
 5    .disable
 6    {
 7        border-style:none; 
 8        border-width: thin; 
 9        background-color:Transparent; 
10        color: #CCCCCC; 
11        cursor:wait;
12    }

13    
</style>
14    <script type="text/javascript" language="javascript">
15    function DisableButton()
16    {
17        document.getElementById("Button2").className  = "disable";
18        document.getElementById("Button2").value = '正在提交.';
19        document.getElementById("Button2").onclick=Function("return false;");
20        return true;
21    }

22    document.onkeydown=mykeydown;   
23    function   mykeydown()
24    {   
25        if(event.keyCode==116//屏蔽F5刷新键   
26        {   
27            window.event.keyCode=0;   
28            return   false;   
29        }
   
30    }
   
31    
</script>
32
33</head>
34<body>
35    <form id="form1" runat="server">
36    <div>
37        输入一些内容<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
38        <br />
39        <asp:ListBox ID="ListBox1" runat="server" Height="77px" Width="332px">
40    </asp:ListBox><br />
41        <asp:Button ID="Button2" runat="server" Text="OK" Width="77px"
42            onclick="Button2_Click" />
43    </div>
44    
45    </form>
46</body>
47</html>
48

服务器端代码,故意让其延时等待3秒后再输入,以模拟数据库操作等慢速动作。
 1public partial class Default2 : System.Web.UI.Page
 2{
 3    static public int count = 0;
 4    protected void Page_Load(object sender, EventArgs e)
 5    {
 6        if (!IsPostBack)
 7        {
 8            Button2.Attributes.Add("onclick""return DisableButton();");
 9        }

10    }

11
12    protected void Button2_Click(object sender, EventArgs e)
13    {
14        if (TextBox1.Text != string.Empty)
15        {
16            System.Threading.Thread.Sleep(3000);
17            count++;
18            ListBox1.Items.Add(new ListItem("Hello "+TextBox1.Text + "  这是你第" + count.ToString() + "次点击   " + DateTime.Now.ToString()));
19            TextBox1.Text = "";
20        }

21    }

22}

感谢网友大李的建议,<asp:Button ID="btnSumbit" runat="server" UseSubmitBehavior="false" OnClientClick="this.value='Sumbit';this.disabled=true; " Text="Sumbit" OnClick="btnSumbit_Click" />
这个方法比我的更好更简单

Feedback

#1楼    回复  引用  查看    

2008-07-17 23:56 by 大李      
<asp:Button ID="btnSumbit" runat="server" UseSubmitBehavior="false" OnClientClick="this.value='Sumbit';this.disabled=true; " Text="Sumbit" OnClick="btnSumbit_Click" />

用这个方法比较好,防止多次提交。

#2楼    回复  引用  查看    

2008-07-18 05:14 by Bewind      
不错,我AJAX的时候,disable 在传出数据则 true 回调完成之后才 false.刷新,刷新后 input 自然是空值,提交数据前肯定要检测的,空值就传不上数据了。

#3楼    回复  引用    

2008-07-18 08:16 by JuzzPig [未注册用户]
如果是PostBack机制,这样防是远远不够的。不信,你提交后刷新页面试试。

#4楼    回复  引用  查看    

2008-07-18 08:51 by amingo      
function mykeydown()
24 {
25 if(event.keyCode==116) //屏蔽F5刷新键
26 {
27 window.event.keyCode=0;
28 return false;
29 }
30 }


如果不能屏蔽菜单栏或反键中的刷新,有何意义?

#5楼    回复  引用    

2008-07-18 08:59 by vicps [未注册用户]
哈哈,试试在firefox下run.

#6楼 [楼主]   回复  引用  查看    

2008-07-18 09:00 by xujh      
--引用--------------------------------------------------
amingo: function mykeydown()
24 {
25 if(event.keyCode==116) //屏蔽F5刷新键
26 {
27 window.event.keyCode=0;
28 return false;
29 }
30 }


如果不能屏蔽菜单栏或反键中的刷新,有何意义?
--------------------------------------------------------

谢谢,我的这个代码主要还是防止操作人员误操作。

#7楼 [楼主]   回复  引用  查看    

2008-07-18 09:03 by xujh      
--引用--------------------------------------------------
JuzzPig: 如果是PostBack机制,这样防是远远不够的。不信,你提交后刷新页面试试。
--------------------------------------------------------
谢谢,PostBack后就可以进入服务端代码的控制中了,我这个范例中要求关键项必须填写才可以通过,在服务端处理并返回新的页面前可以通过清除关键输入项来使得刷新也无法进行后续处理。

#8楼 [楼主]   回复  引用  查看    

2008-07-18 09:14 by xujh      
--引用--------------------------------------------------

大李:



用这个方法比较好,防止多次提交。

--------------------------------------------------------

谢谢大李,你这个方法更好。

#9楼    回复  引用  查看    

2008-07-18 09:19 by 小龙3      
--引用--------------------------------------------------
大李: &lt;asp:Button ID=&quot;btnSumbit&quot; runat=&quot;server&quot; UseSubmitBehavior=&quot;false&quot; OnClientClick=&quot;this.value='Sumbit';this.disabled=true; &quot; Text=&quot;Sumbit&quot; OnClick=&quot;btnSumbit_Click&quot; /&gt;

用这个方法比较好,防止多次提交。
--------------------------------------------------------
简单!可行!

#10楼    回复  引用  查看    

2008-07-18 09:39 by chinaifne      
这位老兄基本上没有用到asp.net里新增加的特性!
//.net1.1

Button1.Attributes.Add("onclick", "this.disabled=true;" + this.GetPostBackEventReference(this.Button1));

//.net 2.0以上

Button1.Attributes.Add("onclick", "this.disabled=true;" + this.ClientScript.GetPostBackEventReference(Button1, ""));

有这样的事件,可以用来处理。是真实的网页回发,比楼主的5秒要好些吧。

详细可以看我的博客:
http://www.cnblogs.com/chinafine/archive/2008/07/03/1234854.html

#11楼    回复  引用  查看    

2008-07-18 10:06 by S.Sams      
#9楼 @小龙3
如果刷新又重复提交啦,
#1楼 + #4楼 结合是比较好的方案

#12楼    回复  引用  查看    

2008-07-18 10:26 by 红尘中迷茫      
直接Redirect页面不就行了吗?

#13楼    回复  引用  查看    

2008-07-18 11:03 by willieQ      
我是直接使用JQuery

优点:不用每个按钮增加事件
缺点:不能避免刷新
但是一般为了根本解决重复提交,记录都是有版本号的,每次保存时自增,保存时需验证版本是否一致,也能防止多用户同时提交问题。

每次按钮点击后disable掉
$(document).ready(function(){
$("input").click(function(){
$(this).attr("disabled","disabled");
});
}

#14楼    回复  引用    

2008-07-18 11:28 by e1 [未注册用户]
恩,如果使用程序提交,好像是不管用的。

#15楼    回复  引用    

2008-07-18 12:12 by killer123 [未注册用户]
<asp:Button ID="btnSumbit" runat="server" UseSubmitBehavior="false" OnClientClick="this.value='Sumbit';this.disabled=true; " Text="Sumbit" OnClick="btnSumbit_Click" />

有验证控件就不行了~

#16楼    回复  引用    

2008-07-18 12:18 by killer123 [未注册用户]
jquery有验证控件就不行了~

#17楼    回复  引用  查看    

2008-07-18 13:00 by 文炽城      
这样的文章不应该放到首页上来吧。

#18楼    回复  引用  查看    

2008-07-18 14:25 by Henllyee Cui      
@文炽城
您这样说就不太好了,我感觉只要是自己的心得体会就行了。

#19楼    回复  引用  查看    

2008-07-18 15:04 by 吴畏      
我不知道楼主有没有运行自己写的代码,通过清空数据来防止重复提交是行不通的,因为页面刷新是通过“ 简单”重复最新请求来实现的。换句话说,浏览器将缓存已处理的最新请求,并在用户单击页面刷新键时重新发布已处理的请求。

#20楼    回复  引用  查看    

2008-07-18 15:27 by ∈鱼杆      
--引用--------------------------------------------------
吴畏: 我不知道楼主有没有运行自己写的代码,通过清空数据来防止重复提交是行不通的,因为页面刷新是通过“ 简单”重复最新请求来实现的。换句话说,浏览器将缓存已处理的最新请求,并在用户单击页面刷新键时重新发布已处理的请求。
--------------------------------------------------------
我也发现大李提供的方法不行,页面已刷新了。

#21楼    回复  引用    

2008-07-18 16:05 by qisky [未注册用户]
加验证码,提交先就不能重复提交

#22楼    回复  引用  查看    

2008-07-18 16:13 by Microshaoft      
通用的防止F5刷新,重复提交应该在服务器端代码控制!
结合【cookie 时间戳】与【隐藏域 时间戳】对比
我们只要把【cookie 时间戳】每次都刷新
当F5实际浏览器重复提交了上次的 【隐藏域 时间戳】
这种方案适用各种“自己提交给自己Action”的Web: PHP、ASP、JSP

#23楼    回复  引用  查看    

2008-07-18 16:17 by Microshaoft      
<%@ Page language="c#" AutoEventWireup="true"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
    
<HEAD>
        
<title>WebForm1</title>
        
<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
        
<meta name="CODE_LANGUAGE" Content="C#">
        
<meta name="vs_defaultClientScript" content="JavaScript">
        
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
    
<script language="C#" runat="server">
    private bool _IsF5RefreshPostBack;
    protected 
void Page_Load(object sender, EventArgs ea) 
    
{
        
if (IsPostBack)
        
{
            
if (Request.Cookies["cookieTimeStamp"!= null)
            
{
                
//if (Request.Cookies["cookieTimeStamp"].Value != this.label1.Text)
                //不用ViewState 使用 HiddenField 也可
                if (Request.Cookies["cookieTimeStamp"].Value != (string) ViewState["vsTimeStamp"])
                
{
                    _IsF5RefreshPostBack 
= true;
                }

            }

        }

        string timeStamp 
= DateTime.Now.ToString();
        
//this.label1.Text = timeStamp;
        ViewState["vsTimeStamp"= timeStamp;
        HttpCookie cookie 
= new HttpCookie("cookieTimeStamp", timeStamp);
        Response.Cookies.Add(cookie);
        
        
if (_IsF5RefreshPostBack)
        
{
            Response.Write(
"IsRefreshPostBack(F5) in Page Load<br>" );
        }


    }

    
void button1_Click (object sender, EventArgs ea) 
    
{
        
if (_IsF5RefreshPostBack)
        
{
            Response.Write(
"IsRefreshPostBack(F5) in Button Click<br>" );
        }

    }

</script>
    
</HEAD>
    
<body MS_POSITIONING="GridLayout">
        
<form id="Form1" method="post" runat="server">
                
<asp:Button ID="button1" Text="button1" onclick="button1_Click" runat="server" />
        
</form>
    
</body>
</HTML>

#24楼    回复  引用  查看    

2008-07-18 16:22 by Microshaoft      
还有一种方案:
就是不要“自己提交给自己”
可以使用@Page 页面指令 SmartNavigation Attribute

#25楼 [楼主]   回复  引用  查看    

2008-07-19 14:05 by xujh      
呵呵,抛砖引玉。这个功能是大家都要用到的,但是可以看到这么多人有这么多种方法,而且各有优缺点。其他讨论出一个最优的方案来。

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-07-18 09:19 编辑过


相关链接: