天天看點

java http重複送出_Java Web之表單重複送出問題

上篇文章講了驗證碼的制作,提及到了一個問題,就是表單重複送出的問題,可能在上次那個驗證碼中感覺不是那麼的重要

現在我新寫一個例子,轉錢。通過這個例子你就知道表單重複送出有多恐怖了。

先來簡單的介紹一下表單重複送出的3種現象

java http重複送出_Java Web之表單重複送出問題

我們來一個個的實驗,首先我們寫兩個東東,一個jsp,一個Servlet,jsp寫了就不動了,Servlet會變化,我會在不同的現象下貼出代碼

JSP:

轉賬

轉賬金額: 元

Servlet我們會在不同的現象修改,下面直接看

1.伺服器慢或者網絡延遲,我們使用線程模拟一下

先看Servlet

packagecom.vae.RandomCode;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.io.PrintWriter;

@WebServlet("/transform")public class TransformServlet extendsHttpServlet {

@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {

resp.setContentType("text/html;charset=utf-8");

PrintWriter out=resp.getWriter();

String money=req.getParameter("money");try{

Thread.sleep(1000);

}catch(InterruptedException e) {

e.printStackTrace();

}

System.out.println("轉出:" +money);

out.println("轉賬成功");

}

}

運作,如圖:

java http重複送出_Java Web之表單重複送出問題

我點選注冊,其實是轉賬。。。。

然後應該出現一大串的轉賬100,但是不知道怎麼回事,我用線程模拟的情況并沒有出現轉賬多次,是以這裡暫時疑惑

2.已經送出成功,不小心重新整理了頁面

(Servlet代碼删了線程就行了)

java http重複送出_Java Web之表單重複送出問題

我們點選一次

java http重複送出_Java Web之表單重複送出問題

然後我不小心的重新整理了幾次頁面

java http重複送出_Java Web之表單重複送出問題

卧槽???啥情況?我就是不小心重新整理了幾次,就要我多轉出去錢???明顯不合理

3.已經送出成功了,我回退,再次點選送出,我就是這麼的事多.....

java http重複送出_Java Web之表單重複送出問題

我點

java http重複送出_Java Web之表單重複送出問題

我回退

java http重複送出_Java Web之表單重複送出問題

我再點

java http重複送出_Java Web之表單重複送出問題

。。。。。這種情況也是不行的。。。。雖然是使用者自己作死。。。。。但是還是要規避一下。。。。

通過上面3個例子,我們知道了表單重複送出的恐怖,特别是涉及到錢的方面。是以我們要想個辦法來規避這種情況,怎麼辦呢?

想想,我們是不是通過兩次請求就可以實作轉賬了,一次是JSP的按鈕點選,一次是Servlet的擷取資料,那麼我們隻需要保證我們每次的操作,都有這兩次請求就可以了

解決方案:令牌機制

我聽到這個令牌機制就想起了狄仁傑...其實令牌機制就是一個随機數UUID,和我們的驗證碼裡面的那個是一樣的。其原理是

我在JSP頁面點選按鈕發出第一次請求的時候,就把我的令牌(随機數)儲存到Session裡面,并且把令牌傳給Servlet,然後在Servlet裡面判斷兩個是否相等

如果相等,就ok,轉賬,然後立馬銷毀session裡面的令牌,這樣無論你再怎麼重新整理,session裡面已經沒有令牌了,肯定不能轉賬了

話說到此,我們來看看最終的代碼

JSP:

轉賬

//生成一個令牌Stringtoken=UUID.randomUUID().toString();//存放在session中

session.setAttribute("TOKEN_IN_SESSION",token);%>

"> 轉賬金額: 元

Servlet:

packagecom.vae.RandomCode;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.io.PrintWriter;

@WebServlet("/transform")public class TransformServlet extendsHttpServlet {

@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {//表單中的令牌

String tokenInRequest=req.getParameter("token");//session中的令牌

String tokenInSession=req.getSession().getAttribute("TOKEN_IN_SESSION").toString();//比較

if(tokenInRequest.equals(tokenInSession)) {//立馬銷毀session中的令牌再說

req.getSession().removeAttribute("TOKEN_IN_SESSION");//然後幹其他的事

resp.setContentType("text/html;charset=utf-8");

PrintWriter out=resp.getWriter();

String money=req.getParameter("money");

System.out.println("轉出:" +money);

out.println("轉賬成功");

}else{

System.out.println("不讓你轉,重新去頁面轉吧");

}

}

}

運作一下,結果已經ok了,我們使用了令牌機制(就是一個随機數)實作了避免表單的重複送出。