问题描述

shiro在管理session后,在session超时会进行跳转,这里有两种情况需要考虑,一种是ajax方式的请求超时,一种页面跳转请求的超时。

本文从这两个方面分别考虑并处理。

ajax请求超时处理

思路:通过Filter后判定,当前是否session超时,超时判定是否是ajax请求,如果是ajax请求,则在response头部设置session-status值,返回到前端读取到相应值后进行处理

后端Filter代码

package com.cnpc.framework.filter;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session; import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; /**
* * filter过滤器,获取项目路径,设置ajax超时标识
* @author billJiang QQ:475572229
*/
public class SystemFilter implements Filter { public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException,
ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
System.out.println(request.getRequestURL());
String basePath = request.getContextPath();
request.setAttribute("basePath", basePath);
if (!SecurityUtils.getSubject().isAuthenticated()) {
//判断session里是否有用户信息
if (request.getHeader("x-requested-with") != null
&& request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
//如果是ajax请求响应头会有,x-requested-with
response.setHeader("session-status", "timeout");//在响应头设置session状态
return;
}
}
filterChain.doFilter(request, servletResponse); } @Override
public void destroy() { // TODO Auto-generated method stub } @Override
public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }

前端通用ajax处理

注意session-status上下文部分

function ajaxPost(url, params, callback) {
var result = null;
var headers={};
headers['CSRFToken']=$("#csrftoken").val(); $.ajax({
type : 'post',
async : false,
url : url,
data : params,
dataType : 'json',
headers:headers,
success : function(data, status) {
result = data;
if(data&&data.code&&data.code=='101'){
modals.error("操作失败,请刷新重试,具体错误:"+data.message);
return false;
}
if (callback) {
callback.call(this, data, status);
}
},
error : function(err, err1, err2) {
console.log("ajaxPost发生异常,请仔细检查请求url是否正确,如下面错误信息中出现success,则表示csrftoken更新,请忽略");
console.log(err.responseText);
if(err && err.readyState && err.readyState == '4'){
var sessionstatus=err.getResponseHeader("session-status");
if(sessionstatus=="timeout"){
//如果超时就处理 ,指定要跳转的页面
window.location.href=basePath+"/" ;
}
else{//csrf异常
var responseBody = err.responseText;
if (responseBody) {
responseBody = "{'retData':" + responseBody;
var resJson = eval('(' + responseBody + ')');
$("#csrftoken").val(resJson.csrf.CSRFToken);
this.success(resJson.retData, 200);
}
return;
}
}
modals.error({
text : JSON.stringify(err) + '<br/>err1:' + JSON.stringify(err1) + '<br/>err2:' + JSON.stringify(err2),
large : true
});
}
}); return result;
}

非ajax请求超时跳转

在本试验中,使用jquery.load方式进行了页面加载,并重载jquery.fn.load改写了该方法,通过beforeSend去除了ajax标识,由于超时返回的登录页面可能嵌入当前页面,所以需要判断当前获得的页面是否是登录页面,如果是登陆页面,则再经过一次跳转到登陆页(或者首页)。

重载的jquery.fn.load方法如下,注意beforeSendresponseText.startWith部分内容。

var _old_load = jQuery.fn.load;
jQuery.fn.load = function( url, params, callback ) {
//update for HANZO, 2016/12/22
if (typeof url !== "string" && _old_load) {
return _old_load.apply( this, arguments );
} var selector, type, response,
self = this,
off = url.indexOf( " " );
if ( off > -1 ) {
selector = jQuery.trim( url.slice( off ) );
url = url.slice( 0, off );
}
if ( jQuery.isFunction( params ) ) {
callback = params;
params = undefined;
} else if ( params && typeof params === "object" ) {
type = "POST";
}
if ( self.length > 0 ) {
jQuery.ajax( {
url: url,
beforeSend: function( xhr ) {
xhr.setRequestHeader('X-Requested-With', {toString: function(){ return ''; }});
},
type: type || "GET",
dataType: "html",
data: params
} ).done( function( responseText ) {
//console.log(responseText);
response = arguments;
//页面超时跳转到首页
if(responseText.startWith("<!--login_page_identity-->")){
window.location.href=basePath+"/";
}else{
self.html(selector ?
jQuery("<div>").append(jQuery.parseHTML( responseText )).find(selector) :
responseText);
}
} ).always( callback && function( jqXHR, status ) {
self.each( function() {
callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
} );
} );
} return this;
};

可通过设置session的timeout来测试结果。需要注意的是ajax请求要使用ajaxPost方法,该方法统一处理了超时跳转。