客户端和服务器后退操作防止表单重复提交

来源:互联网 发布:视频爬虫 python 编辑:程序博客网 时间:2024/06/06 05:43

       表单重复提交的情况大体有两种:一种是网速卡,造成表单没有提交的假象,用户不停的点击提交。另一种则是用户的故意操作,后退或刷新页面然后重新提交。要做的就是防止这两种情况的表单重复提交。

       防止第一种,我们可以在客户端添加操作防止现象发生,有两种方式,都是通过javascript实现的。第一种方式是在javascript中设置一个变量。初值为false,点击提交按钮之后将变量改为true,并且,在变量为false时按钮有提交作用。代码如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>  <head>    <title>ReapteForm.html</title>    <meta http-equiv="content-type" content="text/html; charset=UTF-8">    <script type="text/javascript">     var competeSign = false;     function check() {       if(!competeSign) {          competeSign = true;          return competeSign;       }else {          alert("不能重复提交表单");          return false;       }     }   </script>  </head>    <body style="background-color: white;">    <form action="/learnJS/servlet/RepeateFormServlet" method="post" onsubmit="return check()">       留言内容:<br/>       <textarea rows="10" cols="50"></textarea><br/>       <input type="submit" value="提交"/>    </form>  </body></html>

javascript的第二种方式是,在按钮点击之后变为不可用,这样就不能再提交啦。代码为:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>  <head>    <meta http-equiv="content-type" content="text/html; charset=UTF-8">    <script type="text/javascript">    function dosubmit() {      var input = document.getElementById("submit");      input.disabled = 'disabled';      return true;    }    </script>  </head>    <body style="background-color: white;">      <form action="/learnJS/servlet/RepeateFormServlet" method="post" onsubmit="return dosubmit();">       留言内容:<br/>       <textarea rows="10" cols="50"></textarea><br/>       <input type="submit" id="submit" value="提交"/>       </form>  </body></html>
再有就是在服务器端通过session方式防止表单的重复提交,这样只能防止后退操作,不能防止刷新操作的。思路是,在页面的表单中有一个隐藏项,每一个表单都有一个唯一的标号,同时session中设置一个属性域,通过标号和属性域的比对操作,确定表单是否为重复提交。页面代码为:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@page import="com.you.learn.TokenProcessor"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>  <head>    <title>FormGenerate.jsp</title>    <meta http-equiv="content-type" content="text/html; charset=UTF-8">    <script type="text/javascript">      function beformsubmit() {       var p1 = document.getElementById("p1").value;       if(p1==""){ alert("请输入内容!");     return false;         }       return true;      }    </script>  </head>    <body style="background-color: white;">  <%    TokenProcessor.getInstance().saveToken(request);    String token = (String)request.getSession().getAttribute(TokenProcessor.FORM_TOKEN_KEY);    String name = TokenProcessor.FORM_TOKEN_KEY;    System.out.println("html:" + token);   %>    <form action="/learnJS/servlet/FormDealServlet" method="post" onsubmit="return beformsubmit();">    <input type="hidden" name="<%=name %>" value="<%=token %>">     字段1:<input type="text" name="p1" id="p1"/><br/>     <input type="submit" value="提交"/>    </form>  </body></html>

处理页面的servlet页面代码为:

package com.you.servlet;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.you.learn.TokenProcessor;public class FormDealServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();request.getParameter("TokenProcessor.FORM_TOKEN_KEY");TokenProcessor tokenProcessor = TokenProcessor.getInstance();if(!tokenProcessor.isTokenValid(request)) {out.println("这是重复或非法提交!");response.sendRedirect("/learnJS/FormGenerate.jsp");return;}String p1 = request.getParameter("p1");if(p1 == null || p1.trim().equals("")) {out.println("请输入内容!");}else {out.println("提交内容已被处理!");tokenProcessor.resetToken(request);}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

还有一个Java工具类,用于生成标号:

package com.you.learn;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import sun.misc.BASE64Encoder;public class TokenProcessor {private long previous;//上次生成表单标识号的时间值private static TokenProcessor instance = new TokenProcessor();public static String FORM_TOKEN_KEY = "FORM_TOKEN_KEY";private TokenProcessor() {}@SuppressWarnings("unused")public static TokenProcessor getInstance() {return instance;}/* * 验证请求消息中的标识号是否有效,如果验证请求消息中的标识号和 * 用户session域中的标识号相同,返回结果为true,否则返回false *  */public synchronized boolean isTokenValid(HttpServletRequest request) {/* * 为避免session对象不存在时创建session对象, * 下面的语句不用request.getSession() */HttpSession session = request.getSession(false);if(session == null) {return false;}String saved = (String)request.getSession().getAttribute("FORM_TOKEN_KEY");System.out.println("Token:" + saved);if(saved == null) {return false;}String token = request.getParameter("FORM_TOKEN_KEY");System.out.println("Token+token:" + token);if(token == null) {return false;}System.out.println("equals:" + saved.equals(token));return saved.equals(token);}/** * 清除存储在当前用户session中的表单标识号 */public synchronized void resetToken(HttpServletRequest request) {HttpSession session = request.getSession(false);if(session == null) {return;}session.removeAttribute(FORM_TOKEN_KEY);}/** * 产生表单标识号,并将保存到当前用户的session中 */public synchronized void saveToken(HttpServletRequest request) {HttpSession session = request.getSession();try {byte[] id = session.getId().getBytes();long current = System.currentTimeMillis();if(current == previous) {current++;} previous = current;byte[] now = String.valueOf(current).getBytes();//获得随机数摘要(128个字节)MessageDigest md = MessageDigest.getInstance("MD5");md.update(id);md.update(now);//base64编码BASE64Encoder encoder = new BASE64Encoder();String token = encoder.encode(md.digest());session.setAttribute(FORM_TOKEN_KEY, token);System.out.println("java:" + session.getAttribute("FORM_TOKEN_KEY"));} catch (NoSuchAlgorithmException e) {e.printStackTrace();}}}

这样就完成了。