经常在工作中测试人员发现一些重复提交的问题,js的ajax重复提交尤为常见(几乎全是)。虽然处理办法有多种,但一般都只是前台js做处理。且这种处理对于个要数据提交处都要做逻辑判断来去防止,如果有多处这种请求不仅工作量大且而且不利于统一管理。
介绍一种处理这种问题的一个办法,虽不是最好最简结的但算是比较好管理且减少工作量的。
1,首先js上做下规范,发送ajax请求可用同一包装方法。这样比较容易对js请求做统一处理,即使有改动也不必要去每处发送请求的地方去查找。
myAjaxs = { /* * 请求获取后台数据统一调用 * @param {object} param{ * type : '', get/post * url : '', 请求URL * dataType: '', json或其他 * data : {}, 参数 * succFun : function(){}, 成功回调函数 * errFun : function(){} 失败回调函数 * } */ ajax : function(param){ if(!param){ return; } var params = { type : 'post', dataType : 'json', data : {'token' : token , 'date':new Date().getTime()} }; $.extend(params,param); var obj = {}; obj.url = params.url; obj.type = params.type; obj.dataType = params.dataType; obj.data = params.data; obj.complete = function(XMLHttpRequest, textStatus){ //这里请求完成后回调函数 (请求成功或失败时均调用), //所以我们这里来做防止重复ajax提交当然也可放在成功能回调里去做 上面传参 'token' : token //这里的token设为一个全部变量用于保存后台传过来的 //当后台有token传过来就覆新值否则不变 token = XMLHttpRequest.token || token; } if(param.succFun){ obj.success = function(json){ //你要处理的逻辑 param.succFun.apply(null,[params,resjson]); }; } if(params.errFun){ obj.error = function(request, textStatus, errorThrown){ //你要处理的逻辑 param.errFun.apply(null,[request,textStatus,errorThrown,params]); }; } return $.ajax(obj); } };
2,后台java处理,这里要使用到拦截器(工程中没用到struts的可以用过滤器去实现)。建一个方法拦截器类,这拦截器配制只拦截你所要拦截的方法(有ajax数据提交的方法),当然也可以自己去指定那些特定action用这个拦截器。在拦截器里面我们要做一个token处理,类似struts自带的token防页面重复提交。
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
// 生成一个随机码,用作防止重复提交
String newToken = String.valueOf(System.currentTimeMillis());
String requetToken = request.getParameter("token");
Object token = session.getAttribute("ajax_token");
String retStr;
if(token == null){
session.setAttribute("ajax_token", newToken);
retStr = print("{\"token\" :" + newToken },invocation);
}else if(requetToken.equals(token.toString())){
session.setAttribute("ajax_token", newToken);
retStr = print("{\"token\" :" + newToken ,invocation);
}else{
retStr = Action.SUCCESS;
}
return retStr;
}
private String print(String msg,ActionInvocation invocation) throws IOException{
HttpServletResponse response = ServletActionContext.getResponse();
PrintWriter out = response.getWriter();
out.print(msg);
out.flush();
out.close();
return invocation.invoke();
}
/*这种方法实现也存在着问题,如果可以提交后要反回一些json数据从action那里,而这种改变不了action json的值只能覆盖,所以也不通用。同时还存在着由于网络原因或是其它导致token从服务器端传不到js回调函数中的原因,导致请求都不能提交。大家可以根据自己项目中实现问题再去小小改动*/