客户端服务端防止用户重复提交表单

来源:互联网 发布:linux命令 system dd 编辑:程序博客网 时间:2024/05/11 23:48

一、什么是表单重复提交?
当网络有延迟时,用户提交的表单等数据还没有完成此次提交,但用户又多次点击提交,造成用户数据在数据库或存储中被提交多次。
利用线程延迟,简单模拟重复提交。
表单页面为form.html
[html] view plain copy



form.html

<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  <meta http-equiv="description" content="this is my page">  <meta http-equiv="content-type" content="text/html; charset=UTF-8">  <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->  



用户名 :



处理提交请求的servlet为DoFormServlet.java
[java] view plain copy
package SessionDemo;

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;

public class DoFormServlet extends HttpServlet
{

public void doGet(HttpServletRequest request, HttpServletResponse response)          throws ServletException, IOException  {      String username = request.getParameter("username");      //利用线程休眠,模拟网络延迟      try      {          Thread.sleep(1000*3);      } catch (InterruptedException e)      {          e.printStackTrace();      }      System.out.println("向数据库中注册数据。");  }  public void doPost(HttpServletRequest request, HttpServletResponse response)          throws ServletException, IOException  {      doGet(request, response);  }  

}
在浏览器中加载form.html

当用户反复点击“提交”时,就造成了重复提交。

二、解决方法一:利用javascript阻止
其他不变,将form.html修改为
[html] view plain copy



form.html

<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  <meta http-equiv="description" content="this is my page">  <meta http-equiv="content-type" content="text/html; charset=UTF-8">  <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->  


var isCommitted = false;
function dosubmit()
{
if(!isCommitted)
{
isCommitted=true;
return true;
}
else
{
return false;
}
}




用户名 :




这样在浏览器中加载form.html后,点击“提交”,终端中只会输出一次”向数据库中注册数据。”,表明成功阻止表单反复提交。
以上form.html可以进一步优化,当用户点击“提交”后,“提交”按钮应该变为灰色不可用。
[html] view plain copy



form.html

<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  <meta http-equiv="description" content="this is my page">  <meta http-equiv="content-type" content="text/html; charset=UTF-8">  <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->  


function dosubmit()
{
var input = document.getElementById("submit");
input.disabled = 'disabled';
return true;
}




用户名 :




利用javascript的方法不能完全防止用户恶意重复提交,例如:用户可以将form.html保存后修改,还可以在点击“提交”后重复刷新页面,从而实现反复提交。
三、解决方法二:利用服务器端Session防止表单重复提交。
其中FormServlet.java为
[java] view plain copy
package SessionDemo;

import java.io.IOException;
import java.io.PrintWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import sun.misc.BASE64Encoder;

public class FormServlet extends HttpServlet
{

public void doGet(HttpServletRequest request, HttpServletResponse response)          throws ServletException, IOException  {      //产生随机数表单号      TokenProcessor tp = TokenProcessor.getInstance();      String token = tp.generateToken();      request.getSession().setAttribute("token",token);      request.getRequestDispatcher("/form.jsp").forward(request, response);  }  public void doPost(HttpServletRequest request, HttpServletResponse response)          throws ServletException, IOException  {      doGet(request, response);  }  

}

//设计为单例模式
class TokenProcessor
{
private TokenProcessor(){};
private static final TokenProcessor instance = new TokenProcessor();

public static TokenProcessor getInstance()  {      return instance;  }  public String generateToken()  {      //获得随机数字符串      String token = System.currentTimeMillis() + new Random().nextInt() + "";      //获得数据摘要      try      {          MessageDigest md = MessageDigest.getInstance("md5");          byte[] md5 = md.digest(token.getBytes());          //利用base64编码防止乱码。          BASE64Encoder encoder = new BASE64Encoder();          return encoder.encode(md5);      } catch (NoSuchAlgorithmException e)      {          throw new RuntimeException(e);      }  }  

}
添加form.jsp
[plain] view plain copy
<%@ page language=”java” import=”java.util.*” pageEncoding=”UTF-8”%>







用户名




将DoFormServlet.java修改为
[java] view plain copy
package SessionDemo;

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;

public class DoFormServlet extends HttpServlet
{

public void doGet(HttpServletRequest request, HttpServletResponse response)          throws ServletException, IOException  {      String username = request.getParameter("username");      boolean b = isTokenValue(request);      if (!b)      {          System.out.println("请不要重复提交。");          return;      }      request.getSession().removeAttribute("token");      System.out.println("向数据库中注册数据。");  }  //判断表单号是否有效  private boolean isTokenValue(HttpServletRequest request)  {      String clientToken = request.getParameter("token");      if(clientToken==null)      {          return false;      }      String serverToken = (String) request.getSession().getAttribute("token");      if(serverToken==null)      {          return false;      }      if (!clientToken.equals(serverToken))      {          return false;      }      return true;  }  public void doPost(HttpServletRequest request, HttpServletResponse response)          throws ServletException, IOException  {      doGet(request, response);  }  

}
再浏览器中加载FormServlet

点击“提交”后跳转

终端显示用户提交

这时即使用户点击“刷新”,也不能实现重复提交。

原创粉丝点击