前两天做项目在处理session失效时使用springMVC拦截器拦截ajax请求,结果发现正常请求拦截没问题,ajax请求拦截到了,可是ajax success函数捕获数据是登录页的源码,查了一下资料 ,
https://my.oschina.net/zhk/blog/323452
明白了怎么回事 具体来说ajax是用XMLHttpRequest 对象用于和服务器交换数据。它的请求头区别于正常请求头,利用它的这个特点我们在它请求时将它与正常请求区别开来,既然在拦截器中重定向会被ajax中的success函数捕获登录页源码无法跳转登录页,那么我们可以采取在拦截器中设置响应头添加session失效标记的方法,并用jquery ajax中的complete事件得到响应头中的标记,在js中添加session失效时跳转页面的处理
关于complete事件【
complete(XHR, TS)
类型:Function
请求完成后回调函数 (请求成功或失败之后均调用)。
参数: XMLHttpRequest 对象和一个描述请求类型的字符串。
这是一个 Ajax 事件。
】
以下是我自己测试的代码
Spring-mvc.xml配置
<mvc:interceptors>
<mvc:interceptor>
<!--需要过滤的路径映射 -->
<mvc:mapping path="/**" />
<!—不过滤的路径映射-->
<mvc:exclude-mapping path="/css/**"/>
<mvc:exclude-mapping path="/fonts/**"/>
<mvc:exclude-mapping path="/images/**"/>
<mvc:exclude-mapping path="/js/**"/>
<mvc:exclude-mapping path="/ueditor/**"/>
<mvc:exclude-mapping path="/upload/**"/>
<!—自定义的拦截器注册-->
<bean class="com.rescam.interceptor.AuthInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
自定义拦截器代码
package com.rescam.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
//继承HandlerInterceptorAdapter类
public class AuthInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
String ctxPath = request.getContextPath();//获取项目名
String uri = request.getRequestURI();//获取请求资源名
String qs = request.getQueryString();//获取请求参数
String ctrlName = uri.replace(ctxPath + "/", "");//去掉请求资源名中的项目名
Object user = session.getAttribute("manager");
/*
此处逻辑是先判断session是否失效
然后排除登录页
接着根据请求头判断是正常请求还是ajax请求
*/
if (user == null) {
//注:此处排除登录页的逻辑处理针对我测试的项目,不是固定的(根据项目实际情况灵活处理)
if((qs==null&& !ctrlName.equalsIgnoreCase("manger/login")) ||
(qs != null &&!qs.equalsIgnoreCase("url=login"))) {
if (request.getHeader("x-requested-with") != null &&
request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
response.setHeader("sessionstatus", "timeout");//设置session失效时的响应头标记
} else {
response.sendRedirect(ctxPath + "/page/show?url=login");
}
return false;
}
}
return true;
}
}
jquery ajax请求中需要加上
$.ajax({
url : basePath+'/colorScheme/deletes',
type : 'post',
data : {
'colorSchemeIds' : dels
},
dataType : 'json',
success : function(data) {
//此处在session失效时ajax请求被拦截器拦截到后 返回的是一个响应头
//同时success回调函数依然会执行 只不过此时data是 null 因此我在此加上if
//防止session失效时执行下面程序时报错
if(data && data != null){
if (data.success) {
dt.ajax.reload(null, false);
}
}
},
complete : function (XMLHttpRequest, textStatus) {
//使用XMLHttpRequest对象获取session失效响应头标记
var sessionstatus = XMLHttpRequest.getResponseHeader("sessionstatus"); if(sessionstatus=="timeout"){
//跳转登录页
window.location.replace(basePath + "/page/show?url=login");
}
},
error : function(){
alertMsg("请求失败!");
}
});
});
经过测试 ,在session失效时 jquery ajax请求成功跳转登录页
注:对于
.post()、
.
p
o
s
t
(
)
、
.get()需要特别处理一下
以下摘自
http://www.css88.com/jqapi-1.9/jQuery.post/
从 jQuery 1.5开始,success回调函数还传递一个“jqXHR”对象 ( 在 jQuery 1.4中 ,它传递的是XMLHttpRequest对象)。用 POST 获取的页面是从来不会被缓存, 所以这些请求中的 cache 和 ifModified 选项在 jQuery.ajaxSetup() 是无效的。
The jqXHR Object(jqXHR 对象)
从jQuery 1.5开始,所有jQuery的Ajax方法都返回一个XMLHTTPRequest对象的超集。这个通过
.post()方法返回的jQueryXHR对象,或“jqXHR”,实现了Promise接口,使它拥有Promise的所有属性,方法和行为(见Deferred对象获取更多信息)。jqXHR.done()(表示成功),jqXHR.fail()(表示错误),和jqXHR.always()(表示完成,无论是成功或错误;在jQuery1.6中添加)方法接受一个函数参数,用来请求终止时被调用。关于这个函数接收参数的详细信息,请参阅jqXHRObject文档中的
.
p
o
s
t
(
)
方
法
返
回
的
j
Q
u
e
r
y
X
H
R
对
象
,
或
“
j
q
X
H
R
”
,
实
现
了
P
r
o
m
i
s
e
接
口
,
使
它
拥
有
P
r
o
m
i
s
e
的
所
有
属
性
,
方
法
和
行
为
(
见
D
e
f
e
r
r
e
d
对
象
获
取
更
多
信
息
)
。
j
q
X
H
R
.
d
o
n
e
(
)
(
表
示
成
功
)
,
j
q
X
H
R
.
f
a
i
l
(
)
(
表
示
错
误
)
,
和
j
q
X
H
R
.
a
l
w
a
y
s
(
)
(
表
示
完
成
,
无
论
是
成
功
或
错
误
;
在
j
Q
u
e
r
y
1.6
中
添
加
)
方
法
接
受
一
个
函
数
参
数
,
用
来
请
求
终
止
时
被
调
用
。
关
于
这
个
函
数
接
收
参
数
的
详
细
信
息
,
请
参
阅
j
q
X
H
R
O
b
j
e
c
t
文
档
中
的
.ajax() 章节。
Promise 接口也允许jQuery的Ajax方法, 包括 $.get(), 在一个单独的请求中关联到 .done(), .fail(), 和 .always() 回调函数, 甚至允许你在请求已经结束后,指派回调函数。如果该请求已经完成,则回调函数会被立刻调用。
var jqxhr = $.post("example.php", function() {
alert("success");
})
.success(function() { alert("second success"); })
.error(function() { alert("error"); })
.complete(function() { alert("complete"); });
// perform other work here ...
// Set another completion function for the request above
jqxhr.complete(function(){ alert("second complete"); });
jqXHR.success(), jqXHR.error(), 和 jqXHR.complete() 回调方法 在jQuery 1.5中引进, 在jQuery 1.8中不赞成使用,已经过时。他们最终将被取消(移除),你的代码应该为此做好准备, 从jQuery 3.0开始被删除,你可以使用 jqXHR.done(), jqXHR.fail(), 和 jqXHR.always() 代替.
对了 还有使用关于jquery插件,例如 jquery.Form 、 jquery.fileupload…….时session失效时发送的ajax请求不会被拦截器拦截到,这是因为这些插件已经将ajax请求封装了起来,同时进行了一些加工,已于原本的ajax请求大不相同,不过不用担心,这些插件都有一个共同特点,即都有一个在请求提交之前的事件,例如jquery.FileUpload中的add事件、jquery.Form中的beforeSubmit事件,因此只需在这些事件中加入一个正常的ajax请求即可(例如:空请求 没有任何逻辑处理 只需在此ajax请求中的complete事件中加入session 是否失效的逻辑即可 返回 true or false)
这可能只是解决这个问题的一种方法,希望大家多多分享解决各种技术问题的经验办法,不仅帮助别人,也是帮助自己加深对于这个问题的理解和提高解决问题的能力。只有付出你才能拥有更多。