论坛首页 Java企业应用论坛

避免表单重复提交

浏览 19177 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (1) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-01-20  
       偶然发现了一个小问题,在有些人做的信息系统中,在浏览器上选择后退或刷新时,如果在编写程序的时候不处理,很容易导致重复提交,这样原本像服务器发送的“发表帖子”的命令,就会被发送两次或多次,导致在数据库中插入多条记录。那么如何避免这种情况呢?

       其实我们可以在发表帖子的方法开头加上一个if判断即可。
       if (isRedo(request,"topic_add")) {
             //跳转到提示页面,提示用户已经提交过了
        }

       其中isRedo方法定义为:
       private boolean isRedo(HttpServletRequest request, String key) {
             String value = (String) request.getSession().getAttribute(key);
             if (value == null) {
                   return true;
             } else {
                   request.getSession().removeAttribute(key);
             }
       }

       该方法,首先判断session中是否含有名为key的变量。如果没有,就判断是“重复提交”;否则,就判断为“第一次处理”,并将该属性 从session变量中删除,那么在浏览器后退或刷新导致重复提交的时候,再次调用该方法就会发现该属性为空,因此判断为“重复提交”。
       其中,key是在发表帖子的方法中写入到session中去的:
       session.setAttribute("topic_add","topic_add");
       也就是说在页面请求的时候,就会把key写入到session中,并在第一次提交的时候由程序把key从session中删除。从而达到判断是否重复提交的目的。

       除了这种简单的方法以外,一般通常利用Struts同步令牌(Token)机制来解决Web应用中的重复提交问题。该方法的基本原理是:服 务器端在处理到达的request之前,会将request中的Token值与保存在当前用户session中的令牌值进行比较,看是否匹配。在处理完该 request后,且在response发送给客户端之前,将会产生一个新的 Token,该Token除传给客户端以外,也会将用户session中保 存的旧的Token进行替换。这样,如果用户会退到刚才的提交页面并再次提交的话,客户端传过来的Token值和服务器端的不一致,从而有效地防止了重复 提交地发生。利用Struts这种方法和前面给出的方法原理上是一样的,只是在具体实现上不同而已。

初来乍到,欢迎讨论:)
   发表时间:2007-01-20  
jerry_chiang 写道
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 偶然发现了一个小问题,在有些人做的信息系统中,在浏览器上选择后退或刷新时,如果在编写程序的时候不处理,很容易导致重复提交,这样原本像服务器发送的&ldquo;发表帖子&rdquo;的命令,就会被发送两次或多次,导致在数据库中插入多条记录。那么如何避免这种情况呢?<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;其实我们可以在发表帖子的方法开头加上一个if判断即可。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(isRedo(request,&quot;topic_add&quot;))&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//跳转到提示页面,提示用户已经提交过了<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;其中isRedo方法定义为:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;boolean&nbsp;isRedo(HttpServletRequest&nbsp;request,&nbsp;String&nbsp;key)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;value&nbsp;=&nbsp;(String)&nbsp;request.getSession().getAttribute(key);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(value&nbsp;==&nbsp;null)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;request.getSession().removeAttribute(key);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该方法,首先判断session中是否含有名为key的变量。如果没有,就判断是&ldquo;重复提交&rdquo;;否则,就判断为&ldquo;第一次处理&rdquo;,并将该属性 从session变量中删除,那么在浏览器后退或刷新导致重复提交的时候,再次调用该方法就会发现该属性为空,因此判断为&ldquo;重复提交&rdquo;。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;其中,key是在发表帖子的方法中写入到session中去的:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.setAttribute(&quot;topic_add&quot;,&quot;topic_add&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;也就是说在页面请求的时候,就会把key写入到session中,并在第一次提交的时候由程序把key从session中删除。从而达到判断是否重复提交的目的。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;除了这种简单的方法以外,一般通常利用Struts同步令牌(Token)机制来解决Web应用中的重复提交问题。该方法的基本原理是:服 务器端在处理到达的request之前,会将request中的Token值与保存在当前用户session中的令牌值进行比较,看是否匹配。在处理完该 request后,且在response发送给客户端之前,将会产生一个新的&nbsp;Token,该Token除传给客户端以外,也会将用户session中保 存的旧的Token进行替换。这样,如果用户会退到刚才的提交页面并再次提交的话,客户端传过来的Token值和服务器端的不一致,从而有效地防止了重复 提交地发生。利用Struts这种方法和前面给出的方法原理上是一样的,只是在具体实现上不同而已。<br />
<br />
初来乍到,欢迎讨论:)
Struts的Token在Session只保存一个属性,我用open方式打开多个窗口,结果经常提交失败.应该每次请求在session中保存的token的属性名不同更合理一些.
0 请登录后投票
   发表时间:2007-01-20  

jerry_chiang 写道:
       偶然发现了一个小问题,在有些人做的信息系统中,在浏览器上选择后退或刷新时,如果在编写程序的时候不处理,很容易导致重复提交,这样原本像服务器发送的“发表帖子”的命令,就会被发送两次或多次,导致在数据库中插入多条记录。那么如何避免这种情况呢?

       其实我们可以在发表帖子的方法开头加上一个if判断即可。
       if (isRedo(request,"topic_add")) {
             //跳转到提示页面,提示用户已经提交过了
        }

       其中isRedo方法定义为:
       private boolean isRedo(HttpServletRequest request, String key) {
             String value = (String) request.getSession().getAttribute(key);
             if (value == null) {
                   return true;
             } else {
                   request.getSession().removeAttribute(key);
             }
       }

       该方法,首先判断session中是否含有名为key的变量。如果没有,就判断是“重复提交”;否则,就判断为“第一次处理”,并将该属性 从session变量中删除,那么在浏览器后退或刷新导致重复提交的时候,再次调用该方法就会发现该属性为空,因此判断为“重复提交”。
       其中,key是在发表帖子的方法中写入到session中去的:
       session.setAttribute("topic_add","topic_add");
       也就是说在页面请求的时候,就会把key写入到session中,并在第一次提交的时候由程序把key从session中删除。从而达到判断是否重复提交的目的。

       除了这种简单的方法以外,一般通常利用Struts同步令牌(Token)机制来解决Web应用中的重复提交问题。该方法的基本原理是:服 务器端在处理到达的request之前,会将request中的Token值与保存在当前用户session中的令牌值进行比较,看是否匹配。在处理完该 request后,且在response发送给客户端之前,将会产生一个新的 Token,该Token除传给客户端以外,也会将用户session中保 存的旧的Token进行替换。这样,如果用户会退到刚才的提交页面并再次提交的话,客户端传过来的Token值和服务器端的不一致,从而有效地防止了重复 提交地发生。利用Struts这种方法和前面给出的方法原理上是一样的,只是在具体实现上不同而已。

初来乍到,欢迎讨论:)


如果用户后退,改了下表单的内容呢?你判断它是重复提交?
0 请登录后投票
   发表时间:2007-01-20  

就像楼上说的,那么lz的方法就失效了。我的做法是让提交按钮失效和token或者再从数据库中查询一遍。

但数据库中再查一遍,我一直没用过。因为我感觉这个代价太高了。

这方面也困惑我好久了,一直也没找到好的解决办法。希望有经验的人指导一下。

还有一种办法是用标志来进行判断是否重复提交(类似事务),是以前看到的后来找不到了。

0 请登录后投票
   发表时间:2007-01-20  
用javascript提交,onclick之后disable按钮,个人觉得是个非常简单有效的方法。
0 请登录后投票
   发表时间:2007-01-21  
bigpanda 写道
用javascript提交,onclick之后disable按钮,个人觉得是个非常简单有效的方法。

对,我也认为这个比Struts token更合适。Struts Token不适合打开多个表单,分别提交的情况,如果设置多个有效Token,我觉得无法合理的判断有效的Token.
但Javascript方式,同时要设置浏览器不缓存页面。
0 请登录后投票
   发表时间:2007-01-21  
http://book.csdn.net/bookfiles/175/1001757886.shtml,webwork中使用表单标记(token)防止重复提交.
0 请登录后投票
   发表时间:2007-01-21  
目前我的做法是用一个Hidden域,默认为0,onclick后将值设置为1.然后处理页面显示的时候用redirect方式避免F5操作!
0 请登录后投票
   发表时间:2007-01-22  
实现方法很多
感觉用js来disable按钮的方式最简单,用得也很多
0 请登录后投票
   发表时间:2007-01-22  
重定向不就行了吗?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics