51Testing软件测试论坛

标题: Web系统的表单重复提交问题及解决方案 [打印本页]

作者: lsekfe    时间: 2020-10-13 09:50
标题: 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>


  13.   表单处理Servlet



  14. public class FormServlet extends HttpServlet {

  15.        @Override

  16.        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

  17.            try {

  18.                Thread.sleep(2000); // 模拟网络延迟

  19.            } catch (InterruptedException e) {

  20.                e.printStackTrace();

  21.            }

  22.            req.setCharacterEncoding("utf-8");

  23.            System.out.println("对" + req.getParameter("username") + "进行处理");

  24.        }

  25.    }
复制代码
用户重复提交的场景
  只列举了常见的场景
  场景一:表单提交后,因为网络延迟,让用户有时间重复点击提交。
  场景二:表单提交后,用户刷新页面,导致表单重复提交。
  场景三:表单提交后,用户退回上一个页面,再次点击提交。
  场景四:在一个浏览器中,用户打开两个标签页进行提交。
  重复提交的解决方案
  2.1 方案一
  在前端,通过设置一个标识变量,标识表单的提交状态。(只能解决场景一)
  标识变量默认为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>
复制代码
2.2 方案二
  在后端,通过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
以下为方案二测试结果:
场景一

[attach]130157[/attach]
场景二
[attach]130158[/attach]
场景三
[attach]130159[/attach]
场景四(只有后进入的表单页面有最新的Token)
[attach]130160[/attach]






欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2