Web系统的表单重复提交问题

表单页面JSP:

 1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 2 <html>
 3   <head>
 4     <title>表单页面</title>
 5   </head>
 6   <body>
 7     <form action="commit" method="post">
 8       <input type="text" name="username" />
 9       <input type="submit" id="submit"/>
10     </form>
11   </body>
12 </html>

 

表单处理Servlet:

 1 public class FormServlet extends HttpServlet {
 2     @Override
 3     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 4         try {
 5             Thread.sleep(2000); // 模拟网络延迟
 6         } catch (InterruptedException e) {
 7             e.printStackTrace();
 8         }
 9         req.setCharacterEncoding("utf-8");
10         System.out.println("对" + req.getParameter("username") + "进行处理");
11     }
12 }

 

用户重复提交的场景

只列举了常见的场景

场景一:表单提交后,因为网络延迟,让用户有时间重复点击提交。

场景二:表单提交后,用户刷新页面,导致表单重复提交。

场景三:表单提交后,用户退回上一个页面再次点击提交。

 场景四:在一个浏览器中,打开两个标签页进行提交。

 

重复提交的解决方案

 

方案一:在前端,通过设置一个标识变量,标识表单的提交状态。(只能解决场景一)

标识变量默认为false,一旦表单提交触发,会判断标识变量是否为false,如果为false则发送请求并且将标识变量更改为true,如果为true则不发送请求。

 1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 2 <html>
 3   <head>
 4     <title>表单页面</title>
 5     <script type="text/javascript">
 6       var isCommitted = false; // 默认未提交
 7       function doSubmit() {
 8         if (isCommitted == false) {
 9           isCommitted = true; // 改为已提交
10           return true;
11         }else {
12           return false;
13         }
14       }
15     </script>
16   </head>
17   <body>
18     <form action="commit" method="post" onsubmit="return doSubmit()"> <!--通过doSubmit函数,动态地给onsubmit属性赋值-->
19       <input type="text" name="username" />
20       <input type="submit" id="submit"/>
21     </form>
22   </body>
23 </html>

 

方案二:在后端,通过session和唯一Token来判断重复提交。(可以解决四个场景)

服务器通过session为用户保存一个唯一Token,并且给到浏览器,浏览器会将其保存在一个隐藏的域中随表单提交。

当第一次提交时,提交的Token与session中的Token相等,进行相应处理,并且删除session中的Token。

 

1.TokenProcessor的工具类

 1 public class TokenProcessor {
 2     private static final TokenProcessor instance = new TokenProcessor();
 3 
 4     public static TokenProcessor getInstance() {
 5         return instance;
 6     }
 7     public String makeToken() {
 8         String token = String.valueOf(System.currentTimeMillis() + new Random().nextInt(999999999));
 9         try {
10             MessageDigest md = MessageDigest.getInstance("md5");
11             byte md5[] = md.digest(token.getBytes());
12             Base64.Encoder encoder = Base64.getEncoder();
13             return encoder.encodeToString(md5);
14         } catch (NoSuchAlgorithmException e) {
15             e.printStackTrace();
16             return null;
17         }
18     }
19 }

 

2.获取session和Token的Servlet

1 public class GetSessionServlet extends HttpServlet {
2     @Override
3     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
4         String token = TokenProcessor.getInstance().makeToken();
5         System.out.println(token); // 打印Token的值
6         req.getSession(true).setAttribute("token", token);
7         req.getRequestDispatcher("/index.jsp").forward(req, resp);
8     }
9 }

 

3.表单页面JSP

 1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 2 <html>
 3   <head>
 4     <title>表单页面</title>
 5   </head>
 6   <body>
 7     <form action="commit" method="post">
 8       <input type="text" name="username" />
 9       <input type="hidden" name="token" value=${sessionScope.token} />
10       <input type="submit" id="submit"/>
11     </form>
12   </body>
13 </html>

 

4.表单处理Servlet

 1 public class FormServlet extends HttpServlet {
 2     @Override
 3     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 4         try {
 5             Thread.sleep(2000); // 模拟网络延迟
 6         } catch (InterruptedException e) {
 7             e.printStackTrace();
 8         }
 9         req.setCharacterEncoding("utf-8");
10         HttpSession session = req.getSession(false);
11         if (session == null) {
12             System.out.println("未拥有session,不处理");
13             return;
14         }
15         String token = (String)session.getAttribute("token");
16         if (token == null) {
17             System.out.println("session中未拥有Token,不处理");
18             return;
19         }
20         if (req.getParameter("token") == null) {
21             System.out.println("浏览器Token为空,不处理");
22         }
23         if (!token.equals(req.getParameter("token"))) {
24             System.out.println("Token不一致,不处理");
25             return;
26         }
27         session.removeAttribute("token");
28         System.out.println("对" + req.getParameter("username") + "进行处理");
29     }
30 }

 

测试结果:

场景一

Web系统的表单重复提交问题

 

 

场景二

Web系统的表单重复提交问题

 

 

 

场景三

Web系统的表单重复提交问题

 

场景四(只有后进入的表单页面有正确的Token)

 Web系统的表单重复提交问题

 

Web系统的表单重复提交问题

上一篇:Asp.Net MVC 模型绑定


下一篇:网络入侵检测系统(IDS)的安装部署