如果我们项目中使用了struts2,在使用ajax和后端程序进行通讯时,我们常常为了简单采用以下的方法:
ActionContext ac = ActionContext.getContext();
HttpServletResponse response = (HttpSevletResponse)ac.get(StrutsStatics.HTTP_RESPONSE);
response.setContentType("text/html;charset=utf-8");
try {
PrintWriter pw = response.getWriter();
pw.print(data);
} catch(IOException e) {
e.printStackTrace();
}
以上的方法实际上是存在一个漏洞的。因为这个破坏了struts2执行的完整性,在程序运行过程中可能会出现执行步骤颠倒的问题,当然了这种方式带来的其他问题比如和servlet耦合等问题不是这里要讨论的。比如存在以下的一个场景:我们前端页面中使用ajax和后台进行通信,获取后台数据后,根据这个数据来访问程序中其他的URL路径。现在我们在web.xml中配置我们自己的Filter,这个Filter在struts2执行之前记下“开始运行”的日志,在Struts2执行完毕之后再记下“结束运行”的日志。严格意义上正确的执行顺序是:
1)我们的Filter打印日志“开始运行”;
2)Struts2执行完毕返回数据给客户端;
3)我们的Filter打印日志“结束运行”;
4)ajax根据结果进行第二次访问;
但是如果我们采用上边的方式执行,则可能出现这种顺序:
1)我们的Filter打印日志“开始运行”;
2)Struts2执行完毕返回数据给客户端;
3)ajax根据结果进行第二次访问;
4)我们的Filter打印日志“结束运行”;
原因可能是我们调用response的Writer返回数据给客户端时,会新开一个线程来完成这个工作,而struts2在继续完成其他的工作.某些情况下response的工作在struts2完成之前就完成了和客户端的交互,(比如使用struts2的result拦截器完成的工作比较耗时)。如果在正常流程中的第4)步会依赖第3)步的操作,比如完成设置数据到session,在苛刻的环境中第4)步访问过来了,结果第3)步仍然没有设置完毕(比如我们包装了request来解决分布式session的问题,因为分布式缓存来缓存session,如果session比较大或者嵌套比较复杂会比较耗时的情况下)就会出问题。
因此,在struts2一定要谨慎直接使用response来完成一些操作。
解决办法,可以使用struts2自己的返回json数据或者二进制的方式来完成这些工作。