首页 > 技术文章 > 防止表单重复提交

yyz666 2014-10-30 09:45 原文

一:在客户端通过javascript防止表单重复提交

 1 <!DOCTYPE html>
 2 <html>
 3   <head>
 4     <title>form.html</title>
 5     <meta name="keywords" content="keyword1,keyword2,keyword3">
 6     <meta name="description" content="this is my page">
 7     <meta name="content-type" content="text/html; charset=UTF-8">
 8 <script type="text/javascript">
 9               var isCommitted = false;
10               function doSubmit()
11               {
12                   if(isCommitted==false){
13                       isCommitted = true;
14                       return true;
15                   }
16                   return false;
17               }
18 
19 </script>
20   </head>
21   <body>
22   <form action="/test/servlet/FormServlet" method="post"  onsubmit="return dosubmit()">
23   用户名:<input type="text" name="username"/>
24   <br>
25   <input type="submit" value="提交">
26   </form>
27  <br>
28   </body>
29 </html>

还可以提交过后将提交按钮变灰,无法提交

 1 <!DOCTYPE html>
 2 <html>
 3   <head>
 4     <title>form.html</title>
 5     <meta name="keywords" content="keyword1,keyword2,keyword3">
 6     <meta name="description" content="this is my page">
 7     <meta name="content-type" content="text/html; charset=UTF-8">
 8 <script type="text/javascript">
 9 function dosubmit(){
10     var submit = document.getElementById("submit");
11     submit.disabled= "disabled";
12     return true;
13 
14 }
15 </script>
16   </head>
17   <body>
18   <form action="/test/servlet/FormServlet" method="post"  onsubmit="return dosubmit()">
19   用户名:<input type="text" name="username"/>
20   <br>
21   <input type="submit" value="提交"  id="submit">
22   </form>
23  <br>
24   </body>
25 </html>

其实只在前台用javascript是禁不掉恶意用户的恶意操作的,必须在服务端处理。如用户单击”刷新”,或单击”后退”再次提交表单,将导致表单重复提交。但在服务端处理的同时,客户端也要处理,因为javascript最大的好处就是提升用户体验。

二利用session防止表单重复提交

表单页面由servlet程序生成,servlet为每次产生的表单页面分配一个唯一的随机标识号,并在FORM表单的一个隐藏字段中设置这个标识号,同时在当前用户的Session域中保存这个标识号。
当用户提交FORM表单时,负责处理表单提交的serlvet得到表单提交的标识号,并与session中存储的标识号比较,如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。
在下列情况下,服务器程序将拒绝用户提交的表单请求:
存储Session域中的表单标识号与表单提交的标识号不同
当前用户的Session中不存在表单标识号
用户提交的表单数据中没有标识号字段
 1 package cn.itcast.form;
 2 
 3 import java.io.IOException;
 4 import java.io.PrintWriter;
 5 import java.security.MessageDigest;
 6 import java.security.NoSuchAlgorithmException;
 7 import java.util.Random;
 8 
 9 import javax.servlet.ServletException;
10 import javax.servlet.http.HttpServlet;
11 import javax.servlet.http.HttpServletRequest;
12 import javax.servlet.http.HttpServletResponse;
13 
14 import sun.misc.BASE64Encoder;
15 
16 //负责产生表单
17 public class FormServlet extends HttpServlet {
18 
19     public void doGet(HttpServletRequest request, HttpServletResponse response)
20             throws ServletException, IOException {
21 
22         response.setContentType("text/html;charset=UTF-8");
23         PrintWriter out = response.getWriter();
24         
25         String token = TokenProccessor.getInstance().makeToken();
26         request.getSession().setAttribute("token", token);  //在服务器端保存随机数
27         
28         out.println("<form action='/day07/servlet/DoFormServlet' method='post'>");
29             out.write("<input type='hidden' name='token' value='"+token+"'>");
30             out.println("用户名:<input type='text' name='username'>");
31             out.println("<input type='submit' value='提交'>");
32         out.println("</form>");
33     }
34 
35     public void doPost(HttpServletRequest request, HttpServletResponse response)
36             throws ServletException, IOException {
37 
38         doGet(request, response);
39     }
40 }
41 //工具类生成表单标识号
42 class TokenProccessor{
43     
44     /*
45      *单态设计模式(保证类的对象在内存中只有一个)
46      *1、把类的构造函数私有
47      *2、自己创建一个类的对象
48      *3、对外提供一个公共的方法,返回类的对象
49      * 
50      */
51     private TokenProccessor(){}
52     
53     private static final TokenProccessor instance = new TokenProccessor();
54     
55     public static TokenProccessor getInstance(){
56         return instance;
57     }
58     
59     
60     public String makeToken(){  //checkException
61         
62         //  7346734837483  834u938493493849384  43434384
63         String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
64         //产生固定长度的随机数
65         //数据指纹   128位长   16个字节  md5
66         try {
67             MessageDigest md = MessageDigest.getInstance("md5");
68             byte md5[] =  md.digest(token.getBytes());
69             
70             //base64编码--任意二进制编码明文字符   
71             BASE64Encoder encoder = new BASE64Encoder();
72             return encoder.encode(md5);
73             
74         } catch (NoSuchAlgorithmException e) {
75             throw new RuntimeException(e);
76         }
77         
78     }
79     
80 }
 1 package cn.itcast.form;
 2 
 3 import java.io.IOException;
 4 import java.io.PrintWriter;
 5 
 6 import javax.servlet.ServletException;
 7 import javax.servlet.http.HttpServlet;
 8 import javax.servlet.http.HttpServletRequest;
 9 import javax.servlet.http.HttpServletResponse;
10 
11 public class DoFormServlet extends HttpServlet {
12 
13     public void doGet(HttpServletRequest request, HttpServletResponse response)
14             throws ServletException, IOException {
15 
16         
17         boolean b = isToken(request);  //判断用户是否是重复提交
18         if(b==true){
19             System.out.println("请不要重复提交");
20             return;
21         }
22         
23         request.getSession().removeAttribute("token");
24         //移除session中的随机数
25         System.out.println("处理用户提交请求!!");
26         
27     }
28 
29     private boolean isToken(HttpServletRequest request) {
30         
31         String client_token = request.getParameter("token");//客户机带过来的随机数
32         //没有带随机数过来,说明是恶意用户用自己的form提交到服务端
33         if(client_token==null){
34             return true;
35         }
36         //带了随机数过来,考察服务器保存的随机数
37         String server_token = (String) request.getSession().getAttribute("token");
38         //服务器没有保存随机数,说明服务器处理过这个表单,处理表单后,将session中的这个随机数移除了
39         if(server_token==null){
40             return true;
41         }
42         //用户带过来的随机数和服务器存的不一样,说明是恶意提交
43         if(!client_token.equals(server_token)){
44             return true;
45         }
46         //正常提交
47         return false;
48     }
49 
50     public void doPost(HttpServletRequest request, HttpServletResponse response)
51             throws ServletException, IOException {
52 
53         doGet(request, response);
54     }
55 
56 }

 

推荐阅读