1. 程式人生 > >客戶端服務端防止使用者重複提交表單

客戶端服務端防止使用者重複提交表單

一、什麼是表單重複提交?
當網路有延遲時,使用者提交的表單等資料還沒有完成此次提交,但使用者又多次點選提交,造成使用者資料在資料庫或儲存中被提交多次。
利用執行緒延遲,簡單模擬重複提交。
表單頁面為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

點選“提交”後跳轉

終端顯示使用者提交

這時即使使用者點選“重新整理”,也不能實現重複提交。