客戶端防表單重複提交和伺服器端session防表單重複提交
阿新 • • 發佈:2019-01-23
為了防止使用者在客戶端重複提交表單,要分析從客戶端和服務端對重複提交的表單就行處理,首先是客戶端處理重複提交表單,使用JavaScript方法,第一種是隻允許表單提交一次,後來的不能再提交,第二種是提交一次後按鈕變成不可用,下面是程式碼的實現
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <script type="text/javascript"> /* var isCommit = false; function doSubmit(){ if(! isCommit){ isCommit = true; return true; } else{ return false; } }*/ function doSubmit(){//使提交按鈕再提交完成後不可用 var input = document.getElementById("submit"); input.disabled='disabled'; return true; } </script> </head> <body> <form action="/Web/servlet/DoFormServlet" method="post" onsubmit="return doSubmit()"> 使用者名稱:<input type="text" name="username"><br> <input id="submit" type="submit" value="提交" > </form> </body> </html>
但是僅僅在客戶端進行處理是遠遠不夠的,這叫只能防的了君子防不了小人,因為可以根據伺服器的提交地址自己寫一個表單或者去掉JavaScript程式碼進行自己的提交,這樣仍舊無法阻止客戶端的表單的重複提交,下面就需要在服務端做手腳,首先需要寫一個Servlet用來產生表單,他的想法是產生一個唯一的Id ,通過隨機數才產生,然後付到表單上,當表單提交的時候,根據驗證這個ID號來判斷時候是重複提交表單。
當然,這個隨即數的產生不簡單,首先使用單例設計模式,減少隨機數產生的相似性概率,然後使用當前時間毫秒數加上一個隨機數來進行,然後因為這樣產生的隨機數大小長度不等,所以進行md5編碼後再進行BASE64編碼,產生長度相等的而且字元都是鍵盤上可以識別的隨機數,放到表單的隱藏域裡面去。這個BASE64編碼在網路傳輸中也有很好的作用,表單提交後,處理的Servlet根據放入到Session中的隨機數來驗證是不是重複提交,如果不是,就進行下面的比如放入到資料庫等操作,如果是,則回覆請求,說明表單重複提交。下面上程式碼
首先是產生表單的Servlet
package com.bird.form; import java.io.IOException; 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 { /** * 寫給瀏覽器一個表單,並且防止多次重複提交而建立隨機數 * @author Bird */ private static final long serialVersionUID = 1L; 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{//令牌發生器 /** * 1.把構造方法私有 * 2.自己建立一個 * 3.對外暴露一個方法,允許獲得建立的物件 */ 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 md5 = MessageDigest.getInstance("md5"); byte[] md = md5.digest(token.getBytes()); //base64進行編碼 BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(md); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } }
然後是那個JSP頁面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/Web/servlet/DoFormServlet" method="post">
<input type="hidden" name="token" value="${token}">
使用者名稱:<input type="text" name="username"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
然後是處理提交請求的Servlt
package com.bird.form;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DoFormServlet extends HttpServlet {
/**
* 處理表單的重複提交
* @author Bird
*/
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
boolean b = isTokenValue(request);
if(!b){
System.out.println("請不要重複提交");
return;
}
request.getSession(false).removeAttribute("token");
System.out.println("向資料庫中注入資料");
}
private boolean isTokenValue(HttpServletRequest request) {
String clinet_token = request.getParameter("token");
if(clinet_token == null){
return false;
}
String server_token = (String) request.getSession(false).getAttribute("token");
if(server_token == null){
return false;
}
if(!server_token.equals(clinet_token)){
return false;
}
return true;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}