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

一、什么是表单重复提交?
当网络有延迟时,用户提交的表单等数据还没有完成此次提交,但用户又多次点击提交,造成用户数据在数据库或存储中被提交多次。
利用线程延迟,简单模拟重复提交。
表单页面为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

点击“提交”后跳转

终端显示用户提交

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

原文地址:https://www.cnblogs.com/sean-zeng/p/11024785.html