问题描述
如何防止jsp页面form表单重复提交,注意不是幂等性
问题出现的环境背景及自己尝试过哪些方法
我尝试按照https://m.jb51.net/article/121255.htm里面给出的解决方式去解决。发现第三种情况:表单提交成功以后,直接点击浏览器上回退按钮,不刷新页面,然后点击提交按钮再次提交表单。这里给出的解决方案并不能解决这种情况。
按照情况,可分为三种重复提交的场景:
场景一:在网络延迟的情况下让用户有时间点击多次submit按钮导致表单重复提交
场景二:表单提交后用户点击【刷新】按钮导致表单重复提交
场景三:用户提交表单后,点击浏览器的【后退】按钮回退到表单页面后进行再次提交
对于【场景二】和【场景三】导致表单重复提交的问题,既然客户端无法解决,那么就在服务器端解决,在服务器端解决就需要用到session了。
具体的做法:在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),同时在当前用户的Session域中保存这个Token。然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端,然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。
在下列情况下,服务器程序将拒绝处理用户提交的表单请求:
- 存储Session域中的Token(令牌)与表单提交的Token(令牌)不同。(这种情况我不明白,为什么会出现不同的情况,不应该一直相同吗?)
- 当前用户的Session中不存在Token(令牌)。
- 用户提交的表单数据中没有Token(令牌)。
相关代码
// 请把代码文本粘贴到下方(请勿用图片代替代码)
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%
Date d = new Date();
long dl = d.getTime();
session.setAttribute("uuid", dl);
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>1323132</title>
</head>
<body>
<form action="test" method="get">
<input type="text" name="uuid" value="<%=dl %>"/><br>
user:<input type="text" name="username"><br>
password:<input type="password" name="pwd"><br>
<input type="submit" value="提交"><br>
</form>
</body>
</html>~~~~
package single;
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;
import javax.servlet.http.HttpSession;
public class test extends HttpServlet {
public test() {
super();
}
public void destroy() {
super.destroy();
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String reqUUID = request.getParameter("uuid");
HttpSession session = request.getSession();
String sessUUID = (long) session.getAttribute("uuid")+"";
session.removeAttribute("uuid");
if(reqUUID.equals(sessUUID)){
System.out.println("正常");
}else{
System.out.println("重复提交");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
public void init() throws ServletException {
// Put your code here
}
}
### 你期待的结果是什么?实际看到的错误信息又是什么?
对于场景三,到底如何解决?