您的位置:首页 > 其它

ajax访问遇到Session失效问题

2015-06-11 13:14 423 查看
最近由于一个项目,模块切换为ajax请求数据,当Session失效后,ajax请求后没有返回值,只有响应的html:<html><scripttype='text/javascript'>window.open('http://192.168.0.118:8080/welcomeAction/loginUI.do','_top');</script></html>

现在Ajax在Web项目中应用广泛,几乎可以说无处不在,这就带来另外一个问题:当Ajax请求遇到Session超时,应该怎么办?

显而易见,传统的页面跳转在此已经不适用,因为Ajax请求是XMLHTTPRequest对象发起的而不是浏览器,在验证失败后的页面跳转无法反应到浏览器中,因为服务器返回(或输出)的信息被JavaScript(XMLHTTPRequest对象)接到了。

那么应该怎么处理这种情况呢?

方法

既然服务器返回的消息被XMLHTTPRequest对象接收,而XMLHTTPRequest对象又是在JavaScript的掌控之中,那么我们是否可以利用JavaScript来完成页面跳转呢?

当然可以,而且很容易实现!但有一点,我们需要判断一下HTTP请求是否为Ajax请求(因为AJAX请求和普通的请求需要分开处理),这又如何判断呢?其实Ajax请求和普通的HTTP请求是不同的,这体现在HTTP请求的头信息中,如下所示:





上面两张图片是用火狐的Firebug截取的,前者是普通的HTTP请求头信息;后者为Ajax请求的请求头信息。注意第一图片被红框圈起来的部分,这就是Ajax请求与普通请求不同的地方,AJAX请求头中带有X-Requested-With信息,其值为XMLHttpRequest,这正是我们可以利用的地方。

下面看一下代码如何实现。

Interceptor过滤器

在使用Struts2时,我们一般使用Interceptor(拦截器)来拦截权限问题。

拦截器部分代码:





1publicStringintercept(ActionInvocationinvocation)throwsException{
2//TODOAuto-generatedmethodstub
3ActionContextac=invocation.getInvocationContext();
4HttpServletRequestrequest=(HttpServletRequest)ac.get(StrutsStatics.HTTP_REQUEST);
5StringrequestType=request.getHeader("X-Requested-With");
6System.out.println("+++++++++++++++++++++++reqestType:"+requestType);
7HttpServletResponseresponse=(HttpServletResponse)ac.get(StrutsStatics.HTTP_RESPONSE);
8//StringbasePath=request.getContextPath();
9Stringpath=request.getContextPath();
10StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
11//获取session
12Mapsession=ac.getSession();
13//判断session是否存在及session中的user信息是否存在,如果存在不用拦截
14if(session!=null&&session.get(Constants.FE_SESSION_BG_USER)!=null&&session.get(Constants.FE_SESSION_BG_AUTH)!=null){
15System.out.println(invocation.getProxy().getActionName()+"++++++++++++++++++++++++");
16System.out.println("namespace:"+invocation.getProxy().getNamespace());
17//访问路径
18StringvisitURL=invocation.getProxy().getNamespace()+"/"+invocation.getProxy().getActionName()+Constants.FE_STRUTS_ACTION_EXTENSION;
19visitURL=visitURL.substring(1);
20Map<String,Object>authMap=(Map<String,Object>)session.get(Constants.FE_SESSION_BG_AUTH);
21Map<Integer,String>actionMap=(Map<Integer,String>)authMap.get(Constants.FE_BG_ACTIONMAP);
22if(actionMap!=null&&!actionMap.isEmpty()&&visitURL!=null){
23if(actionMap.containsValue(visitURL)){
24System.out.println(visitURL+"-----------------------");
25returninvocation.invoke();
26}else{
27Stringforbidden=basePath+Constants.FE_BG_FORBIDDEN;
28response.sendRedirect(forbidden);
29returnnull;
30}
31}
32returninvocation.invoke();
33}else{
34if(StringUtils.isNotBlank(requestType)&&requestType.equalsIgnoreCase("XMLHttpRequest")){
35response.setHeader("sessionstatus","timeout");
36response.sendError(518,"sessiontimeout.");
37returnnull;
38}else{
39
40StringactionName=invocation.getProxy().getActionName();
41System.out.println(actionName);
42//如果拦截的actionName是loginUI或login,则不做处理,否则重定向到登录页面
43if(StringUtils.isNotBlank(actionName)&&actionName.equals(Constants.FE_BG_LOGINUI)){
44returninvocation.invoke();
45}elseif(StringUtils.isNotBlank(actionName)&&actionName.equals(Constants.FE_BG_LOGIN)){
46returninvocation.invoke();
47}else{
48Stringlogin=basePath+"/"+Constants.FE_BG_LOGIN_NAMESPACE+"/"+Constants.FE_BG_LOGINUI+Constants.FE_STRUTS_ACTION_EXTENSION;
49//System.out.println("+++++++++++++++++++++++++++basePath:"+basePath);
50//response.sendRedirect(login);
51PrintWriterout=response.getWriter();
52//out.println("<html>");
53//out.println("<script>");
54//out.println("window.open('"+login+"','_top');");
55//out.println("</script>");
56//out.println("</html>");
57out.write("<html><scripttype='text/javascript'>window.open('"+login+"','_top');</script></html>");
58returnnull;
59}
60}
61}
62
63}


ViewCode
由上面代码可以看出,当Session验证失败(即Session超时)后,我们通过HttpServletRequest取得请求头信息X-Requested-With的值,如果不为空且等于XMLHttpRequest,那么就说明此次请求是Ajax请求,我们作出的反应就是向响应中添加一条头信息(自定义)并且使响应对象HttpServletResponse返回服务器错误信息(518状态是自己随便定义的);这些信息都会被JavaScript接收,那么下面的工作就要将由JavaScript代码了。

Javascript代码

$.ajaxSetup方法是来设置AJAX请求默认选项的,我们可以认为是全局的选项设置,因此可以将这段代码提到外部JS文件中,在需要的页面引用。





1/**
2*设置未来(全局)的AJAX请求默认选项
3*主要设置了AJAX请求遇到Session过期的情况
4*/
5$.ajaxSetup({
6type:'POST',
7complete:function(xhr,status){
8varsessionStatus=xhr.getResponseHeader('sessionstatus');
9if(sessionStatus=='timeout'){
10vartop=getTopWinow();
11varyes=confirm('由于您长时间没有操作,session已过期,请重新登录.');
12if(yes){
13top.location.href='/skynk/index.html';
14}
15}
16}
17});
18
19/**
20*在页面中任何嵌套层次的窗口中获取顶层窗口
21*@return当前页面的顶层窗口对象
22*/
23functiongetTopWinow(){
24varp=window;
25while(p!=p.parent){
26p=p.parent;
27}
28returnp;
29}


ViewCode

注册一个典型使用
$.ajaxPrefilter()
的预过滤器,看起来像这样:

1

2

3
$.ajaxPrefilter(function(options,originalOptions,jqXHR){
//Modifyoptions,controloriginalOptions,storejqXHR,etc
});

以下的情况下:

options
是请求的选项

originalOptions
值作为提供给Ajax方法未经修改的选项,因此,没有
ajaxSettings
设置中的默认值

jqXHR
是请求的jqXHR对象

当自定义选项,需要提前处理,预过滤器(Prefilters)是一个完美的选择。给定下面的代码,例如,如果自定义
abortOnRetry
选项被设置为
true
,那么调用
$.ajax()
会自动中止请求相同的URL:

1

2

3

4

5

6

7

8

9

10
varcurrentRequests={};
$.ajaxPrefilter(function(options,originalOptions,jqXHR){
if(options.abortOnRetry){
if(currentRequests[options.url]){
currentRequests[options.url].abort();
}
currentRequests[options.url]=jqXHR;
}
});


.ajaxComplete(handler)

handler

类型:Function(Eventevent,jqXHRjqXHR,PlainObjectajaxOptions
)

被调用的函数。

每当一个Ajax请求完成,jQuery就会触发
ajaxComplete
事件,在这个时间点所有处理函数会使用
.ajaxComplete()
方法注册并执行。

百流积聚,江河是也;文若化风,可以砾石。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: