防止表单重复提交的简单有效的策略
生活随笔
收集整理的這篇文章主要介紹了
防止表单重复提交的简单有效的策略
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
點擊提交按鈕兩次。
點擊刷新按鈕。
使用瀏覽器后退按鈕重復之前的操作,導致重復提交表單。
使用瀏覽器歷史記錄重復提交表單。
瀏覽器重復的HTTP請求。用戶提交表單時可能因為網速的原因,或者網頁被惡意刷新,致使同一條記錄重復插入到數據庫中,這是一個
比較棘手的問題。我們可以從客戶端和服務器端一起著手,設法避免同一表單的重復提交。1、js禁掉提交按鈕。表單提交后使用Javascript使提交按鈕disable。這種方法防止心急的用戶多次點擊按鈕。但有個問題,
如果客戶端把Javascript給禁止掉,這種方法就無效了。2、使用Post/Redirect/Get模式。
在提交后執行頁面重定向,這就是所謂的Post-Redirect-Get (PRG)模式。簡言之,當用戶提交了表單后,
你去執行一個客戶端的重定向,轉到提交成功信息頁面。3、在session中存放一個特殊標志。
在服務器端,生成一個唯一的標識符,將它存入session,同時將它寫入表單的隱藏字段中,然后將表單頁面
發給瀏覽器,用戶錄入信息后點擊提交,在服務器端,獲取表單中隱藏字段的值,與session中的唯一標識符
比較,相等說明是首次提交,就處理本次請求,然后將session中的唯一標識符移除;不相等說明是重復提交,
就不再處理。4.使用header函數轉向
當用戶提交表單,服務器端處理后立即轉向其他的頁面5.在數據庫里添加約束。
在數據庫里添加唯一約束或創建唯一索引,防止出現重復數據。這是最有效的防止重復提交數據的方法。
使用Session防止表單重復提交
一、表單重復提交的常見應用場景有如下的form.jsp頁面<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML> <html><head><title>Form表單</title></head><body><form action="${pageContext.request.contextPath}/servlet/DoFormServlet" method="post">用戶名:<input type="text" name="username"><input type="submit" value="提交" id="submit"></form></body> </html>form表單提交到DoFormServlet進行處理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 {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//客戶端是以UTF-8編碼傳輸數據到服務器端的,所以需要設置服務器端以UTF-8的編碼進行接收, 否則對于中文數據就會產生亂碼request.setCharacterEncoding("UTF-8");String userName = request.getParameter("username");try {//讓當前的線程睡眠3秒鐘,模擬網絡延遲而導致表單重復提交的現象Thread.sleep(3*1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("向數據庫中插入數據:"+userName);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}如果沒有進行form表單重復提交處理,那么在網絡延遲的情況下下面的操作將會導致form表單重復提交多次1.1、場景一:在網絡延遲的情況下讓用戶有時間點擊多次submit按鈕導致表單重復提交1.2、場景二:表單提交后用戶點擊【刷新】按鈕導致表單重復提交場景三:用戶提交表單后,點擊瀏覽器的【后退】按鈕回退到表單頁面后進行再次提交二、利用JavaScript防止表單重復提交采用JavaScript來防止表單重復提交,<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML> <html><head><title>Form表單</title><script type="text/javascript">var isCommitted = false;//表單是否已經提交標識,默認為falsefunction dosubmit(){if(isCommitted==false){isCommitted = true;//提交表單后,將表單是否已經提交標識設置為truereturn true;//返回true讓表單正常提交}else{return false;//返回false那么表單將不提交}}</script></head><body><form action="${pageContext.request.contextPath}/servlet/ DoFormServlet" onsubmit="return dosubmit()" method="post">用戶名:<input type="text" name="username"><input type="submit" value="提交" id="submit"></form></body> </html>針對"在網絡延遲的情況下讓用戶有時間點擊多次submit按鈕導致表單重復提交"這個應用場景, 使用JavaScript是可以解決這個問題的,解決的做法就是"用JavaScript控制Form表單只能提交一次"。除了用這種方式之外,經常見的另一種方式就是表單提交之后,將提交按鈕設置為不可用,讓用戶沒有機會 點擊第二次提交按鈕,代碼如下:function dosubmit(){//獲取表單提交按鈕var btnSubmit = document.getElementById("submit");//將表單提交按鈕設置為不可用,這樣就可以避免用戶再次點擊提交按鈕btnSubmit.disabled= "disabled";//返回true讓表單可以正常提交return true; }使用JavaScript防止表單重復提交的做法只對上述提交到導致表單重復提交的三種場景中的【場景一】 有效,而對于【場景二】和【場景三】是沒有用,依然無法解決表單重復提交問題。對于【場景二】和【場景三】導致表單重復提交的問題,既然客戶端無法解決,那么就在服務器端解決, 在服務器端解決就需要用到session了。在服務器端生成一個唯一的隨機標識號,專業術語稱為Token(令牌),同時在當前用戶的Session域中保存 這個Token。然后將Token發送到客戶端的Form表單中,在Form表單中使用隱藏域來存儲這個Token,表單 提交的時候連同這個Token一起提交到服務器端,然后在服務器端判斷客戶端提交上來的Token與服務器端 生成的Token是否一致,如果不一致,那就是重復提交了,此時服務器端就可以不處理重復提交的表單。如果 相同則處理表單提交,處理完后清除當前用戶的Session域中存儲的標識號。在下列情況下,服務器程序將拒絕處理用戶提交的表單請求: 1.存儲Session域中的Token(令牌)與表單提交的Token(令牌)不同。 2.當前用戶的Session中不存在Token(令牌)。 3.用戶提交的表單數據中沒有Token(令牌)。1.創建FormServlet,用于生成Token(令牌)和跳轉到form.jsp頁面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 FormServlet extends HttpServlet {private static final long serialVersionUID = -884689940866074733L;public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String token = TokenProccessor.getInstance().makeToken(); //創建令牌System.out.println("在FormServlet中生成的token:"+token);request.getSession().setAttribute("token", token); //在服務器使用session保存token(令牌)request.getRequestDispatcher("/form.jsp").forward(request, response); //跳轉到form.jsp頁面}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}2.在form.jsp中使用隱藏域來存儲Token(令牌)<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>form表單</title> </head><body><form action="${pageContext.request.contextPath}/servlet/DoFormServlet" method="post"><%--使用隱藏域存儲生成的token--%><%--<input type="hidden" name="token" value="<%=session.getAttribute("token") %>">--%><%--使用EL表達式取出存儲在session中的token--%><input type="hidden" name="token" value="${token}"/> 用戶名:<input type="text" name="username"> <input type="submit" value="提交"></form> </body> </html>3.DoFormServlet處理表單提交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 {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {boolean b = isRepeatSubmit(request);//判斷用戶是否是重復提交if(b==true){System.out.println("請不要重復提交");return;}request.getSession().removeAttribute("token");//移除session中的tokenSystem.out.println("處理用戶提交請求!!");}/*** 判斷客戶端提交上來的令牌和服務器端生成的令牌是否一致* @param request* @return * true 用戶重復提交了表單 * false 用戶沒有重復提交表單*/private boolean isRepeatSubmit(HttpServletRequest request) {String client_token = request.getParameter("token");//1、如果用戶提交的表單數據中沒有token,則用戶是重復提交了表單if(client_token==null){return true;}//取出存儲在Session中的tokenString server_token = (String) request.getSession().getAttribute("token");//2、如果當前用戶的Session中不存在Token(令牌),則用戶是重復提交了表單if(server_token==null){return true;}//3、存儲在Session中的Token(令牌)與表單提交的Token(令牌)不同,則用戶是重復提交了表單if(!client_token.equals(server_token)){return true;}return false;}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random; import sun.misc.BASE64Encoder;public class TokenProccessor {/**單例設計模式(保證類的對象在內存中只有一個)*1、把類的構造函數私有*2、自己創建一個類的對象*3、對外提供一個公共的方法,返回類的對象*/private TokenProccessor(){}private static final TokenProccessor instance = new TokenProccessor();/*** 返回類的對象* @return*/public static TokenProccessor getInstance(){return instance;}/*** 生成Token* Token:Nv6RRuGEVvmGjB+jimI/gw==* @return*/public String makeToken(){ //checkException// 7346734837483 834u938493493849384 43434384String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";//數據指紋 128位長 16個字節 md5try {MessageDigest md = MessageDigest.getInstance("md5");byte md5[] = md.digest(token.getBytes());//base64編碼--任意二進制編碼明文字符 adfsdfsdfsfBASE64Encoder encoder = new BASE64Encoder();return encoder.encode(md5);} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}} }?
總結
以上是生活随笔為你收集整理的防止表单重复提交的简单有效的策略的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对原生ajax的理解
- 下一篇: web.xml文件中可以配置哪些内容?