如何防止用户重复提交数据

文章介绍了ASP.NET中防止页面刷新导致重复提交数据的方法。包括简单的使用Response.Redirect语句,常规的比较Session ID和ViewState中存储的Session ID,以及利用自定义web控件和HTTP Modules的更简单方法,还说明了其工作原理和实现步骤。

这篇文章从语法上看,原作者应该是从什么地方翻译过来的。

简单的解决方案:
最简单的方式就是当用户提交之后,在你的服务器端控件的代码中使用Response.Redirect("selfPage")语句。但是大多的数包括我都不使用这种方法。

多次提交:
请注意:这篇文章并不是有关如何防止在一个页面中多次提交。这篇文章是教你在提交了请求之后如何防止页面进行刷新。情况是这样的,当用户提交了按钮之后,最终用户就不能再点击提交按钮了。但是这样最终用户仍然可以通过点击浏览器的刷新按钮来提交数据。如果要防止多次提交你可以去 http://metabuilders.com/网上找一些资料,它那里有一个提交控件可以用。

常规的解决方案
习惯的解决方法是存储Session的ID和当提交时ViewState中存储的SessionID相比较来防止用户刷新屏屏幕。前提你的程序中允许了自动回发,如果不是的话,就得在hidden field存储这个变量了。下面给出一个典型的例子。在Page_Load事件中你存储了第一次提交时的SessionID和一个时间戳。
protected System.Web.UI.WebControls.Button SubmitButton;

protected System.Web.UI.WebControls.Label RefreshID;     

private void Page_Load(object sender, System.EventArgs e)

{
     if (RefreshID.Text.Length == 0) 
    {
            RefreshID.Text = Session.SessionID+DateTime.Now.Ticks.ToString();
      }
}
 

private void Button1_Click(object sender, System.EventArgs e)

{
      string sesToken = (string) Session[FrameworkConst.SYNC_CONTROL_KEYWORD];      string pageToken = RefreshID.Text;
      if (sesToken != null && sesToken != pageToken)
      {
            Response.Write("The Refresh was performed after submit.");
     } 
      else
      {
            // do your processing here to avoid Refresh trap
            Response.Write("The processing is done here. Disabling submit
button so that user can not perform multiple submit.");
            Response.Write("But still user can peform Refresh on page.");
      }

      Session[FrameworkConst.SYNC_CONTROL_KEYWORD] =       Session.SessionID+DateTime.Now.Ticks.ToString();
      RefreshID.Text = sesToken;         
      SubmitButton.Enabled = false;

}

 不同的解决方案:
 幸运的事,asp.net提供了一些更简单的方法。上面的解决方案的缺点是我们要在控钮的事件中自己决定一些逻辑问题。设想一下,如果在你的解决方案中有成百个要提交的页面,你就得写上许多个这样的逻辑。自定义web控件和HTTP MOdules提供了相同的解决法。你可以将这个控件入在你需要控制的页面上,它就可以起作用了。当然,并不是所有的情况都需要的,比如说搜索页面是允许用户刷新的。但是,在页面中有插入、更新、删除数据库的操作时,控制刷新按钮是绝对有必要的。

下面来看一下上面的方案是如何工作的。
第一步:需要在System.web节中注册HTTP Module模块。

<httpModules>

   <add name="SyncHttpModule" type="EAD.Controller.SyncHttpModule, sync"/>

</httpModules>

第二步:要在控制页的页面内放入我们开发好的控件。

工作原理:
它的工作原理和前面普通讲的是差不多的。只是这里提供了一个通用的方法。这里提供了一种通用的方式。在我看来,如果你有一些好的模式,将大大的加快你的开发速度。

我们需要在第一次提交时在Session中存储标记,并在请求时比较它们是否不同。通过HTTP handler,我们在Session中存储标记。有这样的一个事件PreRequestHandlerExecute 我们可以通过它找到Session,如果是其它事件的话Session是不存在的,比如BeginRequest 事件。在这个事件中比较两者的值,如果不同则证明是Refresh事件。这时你可以添加自己的处理方法,我一般是将转向一个页面告诉用户不能反复提交。
private void OnPreRequestHandlerExecute(object source, EventArgs e)

{

      HttpContext context = ((HttpApplication) source).Context;

      string _keyword = FrameworkConst.SYNC_CONTROL_KEYWORD;

      string sesToken = (string) context.Session[_keyword];

      string reqToken = context.Request.Params[_keyword];
 //如果没有提交过,则保存Session和标记值

      if(reqToken != FrameworkConst.BYPASS_SYNC_KEYWORD)
      {
            context.Session[_keyword] =             context.Session.SessionID+DateTime.Now.Ticks.ToString();
      }
      if(reqToken != null && reqToken != sesToken)
      {
            string path=context.Request.ApplicationPath+
            &"/Common/SyncControl.aspx?returnUrl="+
            &context.Request.Url.AbsolutePath;
            context.Server.Transfer(path);
      }
}

SyncControl 控件将建立一个hidden input field 将在 HTTP module中设置的Session保存起来。

在Java中防止用户重复提交的常见方法主要包括以下几种: 1. **令牌机制(Token)** 在表单中添加一个隐藏字段,用于存放一个随机生成的令牌(Token)。当用户提交表单时,将令牌一起提交到服务器。服务器接收到请求后,首先检查令牌是否存在,如果不存在则拒绝请求;如果存在,则将令牌从服务器中移除,并处理请求。这样,即使用户多次提交表单,由于令牌已经被移除,后续的请求都会被拒绝[^4]。 2. **使用POST-REDIRECT-GET(PRG)模式** 在处理完POST请求后,服务器不直接返回响应,而是返回一个重定向(REDIRECT)到GET请求的响应。用户的浏览器会根据重定向地址发起一个新的GET请求,服务器再返回最终的响应。这样,即使用户刷新页面,也只会重复发起GET请求,而不会重复提交表单[^4]。 3. **使用AJAX异步提交** 通过AJAX异步提交表单,可以在不刷新页面的情况下将数据发送到服务器。在提交成功后,可以禁用提交按钮,防止用户多次点击[^4]。 ```javascript document.getElementById("submitBtn").addEventListener("click", function() { this.disabled = true; // AJAX 提交逻辑 }); ``` 4. **在服务器端设置限制** 在服务器端可以设置一定的限制,例如限制同一个用户在一定时间内只能提交一次表单。这可以通过记录用户的IP地址和提交时间来实现[^4]。 5. **通过缓存或非关系型数据库** 可以使用缓存或非关系型数据库(如Redis、Memcached)将提交数据通过无法重复的key缓存起来,并异步插入到数据库。由于关系型数据库是key-value形式,不会存储相同的数据进去。这种方法适用于已经集成缓存系统的项目[^2]。 6. **通过数据库限制插入** 在某个字段上设置唯一约束,例如: ```sql ALTER TABLE table_name ADD UNIQUE (column_name); ``` 或者设置联合唯一索引: ```sql ALTER TABLE table_name ADD UNIQUE KEY (column1, column2); ``` 这样,在重复插入时SQL会报异常,可以通过捕获异常后返回异常信息来处理重复提交的问题[^2]。 7. **使用synchronized关键字** 在Java代码中增加`synchronized`关键字,使提交数据一条一条执行。例如: ```java public synchronized Result<?> save(Model model) { return null; } ``` 这种方法虽然实现简单,但性能较低,并且在多实例部署时无法起到作用。 8. **前端控制提交按钮状态** 在前端控制提交按钮的状态,在未返回结果之前禁用按钮,防止用户多次点击。例如: ```javascript document.getElementById("btn").disabled = true; ``` 尽管这种方法无法完全防止恶意用户调用接口提交数据,但在一定程度上可以减少重复提交的发生。 9. **幂等性设计** 幂等性设计是一种常见的防止重复提交的方法。通过在请求中加入唯一标识符(如UUID),确保每次请求的唯一性。服务器端可以记录这些标识符,并在处理请求时检查是否已经处理过相同的请求,从而避免重复操作[^3]。 10. **使用浏览器缓存控制** 在响应头中设置`Cache-Control`为`no-store`,可以禁止浏览器缓存页面。这样,当用户刷新页面时,浏览器会重新请求页面,而不是直接从缓存中加载,从而降低重复提交的风险。 综上所述,Java中防止用户重复提交的解决方案多种多样,具体选择哪种方法取决于项目的实际情况和需求。通常,结合前端和后端的多重控制可以更有效地防止重复提交问题的发生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值