在分布式项目维护中遇到了表单重复提交的问题
第一次出现这个bug时我用了最简单的方式,就是在前台js中控制提交按钮,防止重复点击如下这种方式,依然没有解决问题。
var btnFlag = true;
$("#createOrder").click(function(){
if(btnFlag){
btnFlag = false;
ajax_post(url,param,'json',function(data){
//xxxxxx
});
}
});
第二次 我用上了token ,原理是在jsp页面加载时在session中放入一个时间取到毫秒,再一块hidden 中赋值用ajax传值到后台,进行对比值,如果两值一样,就让提交。
如下,并且,把dubbo 的配置也改了,怕是因为服务多次调用出现的原因,又失败了。
<%
long token=System.currentTimeMillis(); //产生时间戳的token
session.setAttribute("token",token);
%>
<input type="hidden" value="<%=token %>" name="Reqtoken" id="Reqtoken"/> <!-- 作为hidden提交 -->
dubbo 配置
<dubbo:reference id="business.IOrder" interface="com.ailk.helios.center.business.service.IOrder">
<dubbo:method name="createOrderAndSubmit" retries="0" timeout="50000"/>
这回好好分析生产上打出来的日志,发现有从前台传值的log,出现了三次,说明不是dubbo服务的原因,问题出现的时间是间隔2毫秒,客户用的浏览器是UC,测试没有复现。
这个问题就是出现项目本身了,找来了jmeter做后台压力测试,出现了多次请求多次提交的问题(也是好好学习了一下工具呀,也挺有收获的)。本身项目用的是公司自己写的servlet框架,项目中也用了aop,所以在网上找springmvc+token的拦截器方法想进行拦截。放在项目中拦截器竟然不起作用,真是想哭。就想着要不写一个filter吧,因为项目中有很多自己写的filter可以用。但是老大提出了一个方式,加同步块吧。没错synchronized 就是它,在代码中小部分的加上如下,报着试试的心态做了jmeter,用了三个浏览器同时多线程测试,过了。开心呀!
String token = request.getParameter("Reqtoken");// 获取表单上面的时间戳T1
HttpSession session=request.getSession(false);
String tokenInSession = "";
synchronized(session){
tokenInSession = ""+session.getAttribute("token");
session.removeAttribute("token");
}
没有骄傲,怕影响项目,又做了一个防止一个用户阻塞,影响其它用户提交的测试如下,也通过了,三个用户,两个提交正常,一个在阻塞中。。
又做了一个测试,提交订单阻塞中的用户可不可用其它功能,可以用其他功能。ok.就先这样子。
synchronized(session){
tokenInSession = ""+session.getAttribute("token");
session.removeAttribute("token");
if(session.getId().equals("4A8787C63C11A8D78A850BEEAFC0A87C") ){
while(true){
log.info("【阻塞中=================================】【此用户的session= "+session+"\n session.getId()="+session.getId());
}
}
}