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

一、什么是表单重复提交?

当网络有延迟时,用户提交的表单等数据还没有完成此次提交,但用户又多次点击提交,造成用户数据在数据库或存储中被提交多次。

利用线程延迟,简单模拟重复提交。

表单页面为form.html

<!DOCTYPE html>
<html>
  <head>
    <title>form.html</title>
	
    <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">-->

  </head>
  
  <body>
    <form action="/SessionTest/servlet/DoFormServlet" method="post">
    	用户名 :<input type="text" name="username">
				<input type="submit" value="提交">
    </form>
  </body>
</html>

处理提交请求的servlet为DoFormServlet.java

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修改为

<!DOCTYPE html>
<html>
  <head>
    <title>form.html</title>
	
    <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">-->

  <script type="text/javascript">
  	var isCommitted = false;
	function dosubmit()
	{
		if(!isCommitted)
		{
			isCommitted=true;
			return true;
		}
		else
		{
			return false;
		}
	}  
  </script>
  </head>
  <body>
    <form action="/SessionTest/servlet/DoFormServlet" method="post" οnsubmit="return dosubmit()">
    	用户名 :<input type="text" name="username">
				<input type="submit" value="提交">
    </form>
  </body>
</html>

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

<!DOCTYPE html>
<html>
  <head>
    <title>form.html</title>
	
    <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">-->

  <script type="text/javascript">
	function dosubmit()
	{
  		var input = document.getElementById("submit");
		input.disabled = 'disabled';
		return true;
	}  
  </script>
  </head>
  <body>
    <form action="/SessionTest/servlet/DoFormServlet" method="post" οnsubmit="return dosubmit()">
    	用户名 :<input type="text" name="username">
				<input id="submit" type="submit" value="提交">
    </form>
  </body>
</html>

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

其中FormServlet.java为

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

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->

  </head>
  
  <body>
	<form action="/SessionTest/servlet/DoFormServlet" method="post">
		<input type="hidden" name="token" value="${token}">
	用户名<input type="text" name="username">
		<input type="submit" value="提交">
	</form>
  </body>
</html>

将DoFormServlet.java修改为

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

点击“提交”后跳转


 

终端显示用户提交

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值