在程序开发过程中,碰到了一个问题,就是Ajax中Session超时后如何跳转的问题,如果
返回的是javaScript,根本无法执行。解决办法如下:
用eval函数执行javascript,但是又碰到一个问题,如果Session未超时,应该返回正常的数据,怎么办呢?google了一下,下面这篇文章给出了解决方案。
不过我用的是Struts2,用的是Interceptor实现的权限认证。(Interceptor介绍参考:http://www.blogjava.net/max/archive/2006/12/06/85925.html)
场景:一个基于Ajax技术的Web应用,采用的是多页面方式,每个页面内部使用Ajax实现复杂业务逻辑之间的无刷新切换,使用了Struts来实现MVC。
问题:对于Ajax请求,只有在通过用户验证无误之后才能对请求作出响应。如果用户长时间不做操作导致Session过时之后才发出请求,则此时应该跳转到出错页面,提示用户重新登录。对于非Ajax请求,可以自定义异常并针对此异常设置相应的出错页面。在用户信息验证失败的时候直接抛出此异常即可,web容器会自动捕捉到此异常并且显示出错页面;但是,对于Ajax请求,则不会如期待的那样自动跳转到出错页面。若不错特殊处理,Ajax请求的回调函数会得到意想不到的数据而导致程序出错。
分析:对于一个Ajax的应用,每一次客户端和服务器的数据交互,可以看成是在一个由客户端的XMLHttpRequest和服务器端的Servlet(这里假设用Servlet响应Ajax请求)组成的闭合管道(如图1)中进行的:
<!--[if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter"/> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0"/> <v:f eqn="sum @0 1 0"/> <v:f eqn="sum 0 0 @1"/> <v:f eqn="prod @2 1 2"/> <v:f eqn="prod @3 21600 pixelWidth"/> <v:f eqn="prod @3 21600 pixelHeight"/> <v:f eqn="sum @0 0 1"/> <v:f eqn="prod @6 1 2"/> <v:f eqn="prod @7 21600 pixelWidth"/> <v:f eqn="sum @8 21600 0"/> <v:f eqn="prod @7 21600 pixelHeight"/> <v:f eqn="sum @10 21600 0"/> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/> <o:lock v:ext="edit" aspectratio="t"/> </v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" alt="" style='width:299.25pt; height:86.25pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image001.png" o:href="https://p-blog.youkuaiyun.com/images/p_blog_youkuaiyun.com/rikuseiha/1.bmp"/> </v:shape><![endif]-->
图1
所有从服务器端得到的数据流都会被XMLHttpRqeuest对象获得,然后由回调函数做出相应处理。
一般而言,用户登录之后,将用户信息是存放在Session中。做用户验证,其实就是检查此时Session中用户信息是否存在或者是否正确。如果在每次逻辑处理之前都去做这样的重复检查,并且检查的方法会发生改变,这样的程序既不精简还缺少可维护性。相信很少有人这么做。
比较好的做法是使用Filter(Servlet2.3之后才行)来做这样的通用检查,简单而且修改规则也很容易。Filter在应用中的作用之处如图2所示:
<!--[if gte vml 1]><v:shape id="_x0000_i1026" type="#_x0000_t75" alt="" style='width:299.25pt;height:86.25pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image003.png" o:href="https://p-blog.youkuaiyun.com/images/p_blog_youkuaiyun.com/rikuseiha/2.bmp"/> </v:shape><![endif]-->
图2
另外,还可以添加具有不同功能的Filter,形成一个Filter链。
可以看到,在请求还没有到达Servlet之前,可以对请求作一些处理之后再提交给Servlet;在Servlet发出响应但还没有到达客户端之前,还可以对响应作处理。因此,作用户检查之类的工作由Filter来完成是比较合理的。
并不是说经过Filter的请求最终一定会到达Servlet。因为Filter有权操作Request和Response,所以Filter完全可以自己向客户端直接返回响应,从而中止此次交互:
<!--[if gte vml 1]><v:shape id="_x0000_i1027" type="#_x0000_t75" alt="" style='width:299.25pt;height:86.25pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image005.png" o:href="https://p-blog.youkuaiyun.com/images/p_blog_youkuaiyun.com/rikuseiha/3.bmp"/> </v:shape><![endif]-->
图3
如图3所示,若是检查用户信息失败,Filter可以直接返回响应。
到这里,应该比较清楚了,在用户信息验证出错情况下,若要使得客户端能自动显示出错提示页面,应该让Ajax请求所对应的回调函数去做。
如果只是很简单的少数请求,则可以在Filter中返回出错标志,然后在回调函数中作判断进行相应的页面跳转处理。但是,对于一个复杂的应用,如果每个回调函数中都要添加这样的判断,或者服务器端定义的出错标志发生改变,则会大大降低程序的可维护性。
对于稍稍复杂的Ajax应用,一般都会使用一个共通的模块来操作Ajax的请求(比如创建跨浏览器的XMLHttpRequest对象等等)。如果能在这样的通用模块中具有可以在回调函数被调用之前获得服务器返回数据的能力,则可以做通用的出错判断,而不必修改每一个回调函数。
比如下面的这个通用模块:
<!--[if gte vml 1]><v:shape id="_x0000_i1028" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image007.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104022542.gif"/> </v:shape><![endif]-->functionsendRequest(callback,data,method,url,async,sload,user,password)
<!--[if gte vml 1]><v:shape id="_73_537_Open_Image" o:spid="_x0000_i1029" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image008.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104022768.gif"/> </v:shape><![endif]-->{
<!--[if gte vml 1]><v:shape id="_x0000_i1030" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->//创建XMLHttpRequest对象
<!--[if gte vml 1]><v:shape id="_x0000_i1031" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->varoj=createHttpRequest();
<!--[if gte vml 1]><v:shape id="_x0000_i1032" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->if(oj==null)returnnull;
<!--[if gte vml 1]><v:shape id="_x0000_i1033" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->...
<!--[if gte vml 1]><v:shape id="_201_309_Open_Image" o:spid="_x0000_i1034" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image010.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023928.gif"/> </v:shape><![endif]-->if(typeofcallback=='object'){
<!--[if gte vml 1]><v:shape id="_x0000_i1035" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->varcallback_onload=callback.onload;
<!--[if gte vml 1]><v:shape id="_x0000_i1036" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->varcallback_onbeforsetheader=callback.onbeforsetheader;
<!--[if gte vml 1]><v:shape id="_316_396_Open_Image" o:spid="_x0000_i1037" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image010.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023928.gif"/> </v:shape><![endif]-->}else{
<!--[if gte vml 1]><v:shape id="_x0000_i1038" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->varcallback_onload=callback;
<!--[if gte vml 1]><v:shape id="_x0000_i1039" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->varcallback_onbeforsetheader=null;
<!--[if gte vml 1]><v:shape id="_x0000_i1040" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image011.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023453.gif"/> </v:shape><![endif]-->}
<!--[if gte vml 1]><v:shape id="_x0000_i1041" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->
<!--[if gte vml 1]><v:shape id="_425_459_Open_Image" o:spid="_x0000_i1042" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image010.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023928.gif"/> </v:shape><![endif]-->oj.onload=function(){
<!--[if gte vml 1]><v:shape id="_x0000_i1043" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->callback_onload(oj);
<!--[if gte vml 1]><v:shape id="_x0000_i1044" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image011.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023453.gif"/> </v:shape><![endif]-->}
<!--[if gte vml 1]><v:shape id="_x0000_i1045" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->...
<!--[if gte vml 1]><v:shape id="_x0000_i1046" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->oj.open(method,url,async,user,password);
<!--[if gte vml 1]><v:shape id="_x0000_i1047" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->...
<!--[if gte vml 1]><v:shape id="_x0000_i1048" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->oj.send(data);
<!--[if gte vml 1]><v:shape id="_x0000_i1049" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image012.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023625.gif"/> </v:shape><![endif]-->}
可以在callback_onload(oj);之前添加对出错标志的判断。到此处,问题已经得到解决。
如果以后要更改出错标志或者是出错页面,则此处也要做相应的更改才行。如何能更“智能”一点呢?
既然Filter可以返回出错标志,那当然也可以返回javascript代码了!如果能在此处动态地执行一段代码,不就解决问题了吗?想到javascript的eval函数了吧!对,就是它!代码很简单:
<!--[if gte vml 1]><v:shape id="_24_103_Open_Image" o:spid="_x0000_i1050" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image008.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104022768.gif"/> </v:shape><![endif]-->oj.onload=function(){
<!--[if gte vml 1]><v:shape id="_32_61_Open_Image" o:spid="_x0000_i1051" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image010.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023928.gif"/> </v:shape><![endif]-->try{
<!--[if gte vml 1]><v:shape id="_x0000_i1052" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->eval(oj.responseText);
<!--[if gte vml 1]><v:shape id="_73_74_Open_Image" o:spid="_x0000_i1053" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image010.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023928.gif"/> </v:shape><![endif]-->}catch(e){}
<!--[if gte vml 1]><v:shape id="_x0000_i1054" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->
<!--[if gte vml 1]><v:shape id="_x0000_i1055" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image009.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023300.gif"/> </v:shape><![endif]-->callback_onload(oj);
<!--[if gte vml 1]><v:shape id="_x0000_i1056" type="#_x0000_t75" alt="" style='width:8.25pt;height:12pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image012.gif" o:href="http://www.xrss.cn/XrssFile/2007-11/23/20071123104023625.gif"/> </v:shape><![endif]-->}
如果是正常情况下返回的数据,eval函数执行后不会引起程序异常;如果是一段javascript代码,则会得到执行,客户端的Ajax调用也不要做任何修改。
返回到Filter,若是用户验证失败,并且是Ajax请求可以返回一段让页面自动跳转的javascript代码;若是普通的非Ajax请求,则可以放心地抛出异常。经过验证,在Ajax请求和非Ajax请求的情况下,二者的客户体验是相同的。对于页面跳转,其实方法很多,这里就省略代码了。
同理,如果继续添加用户权限检查等等的Filter,则可以地向客户端发出各种不同的javascript代码,很轻松实现相应的功能而客户端无需作修改。
总结:对于Ajax的请求,其数据流是封闭的,服务器发送给在客户端的数据都被XMLHttpRequest对象所获得。本文通过从Filter中发出javascript代码让其在客户端得到执行,从而可以在session过时验证用户信息失败之后,让客户端自动显示出错页面,与非Ajax请求时的客户体验相一致。对于Ajax请求,此方法进一步推广,可以直接在服务器端发出javascript让其在客户端得到执行。
原文来源:http://www.xrss.cn/Dev/AJAX/2007112317765.Html
1万+

被折叠的 条评论
为什么被折叠?



