解决方案:对Angular Ajax的每次请求进行拦截,在请求头增加X-Requested-With标识,后台进行Fiter过滤时,根据X-Requested-With值来判断是否为Ajax请求,如果Session失效且为Ajax请求,则response返回错误编码。Angular拦截的responseError方法中判断是否为Session失效的错误编码,是在js代码中处理Session失效的逻辑操作,比如弹出提示框,跳转至登录界面。
拦截器前台请求
Angular中采用$httpProvider.interceptors拦截方式来做处理Ajax请求,拦截Ajax请求的request、response、responseError错误码状态
- 在AngularJS所有request请求头(Ajax请求)中都加上 X-Requested-With
- 处理responseError方法的Status状态码,判断是否和Filter中response定义的Code一致,符合条件则跳转至登录界面
app.config(['$logProvider', '$httpProvider','$stateProvider','$urlRouterProvider', function($logProvider, $httpProvider,$stateProvider,$urlRouterProvider){
$logProvider.debugEnabled(true);
$urlRouterProvider.otherwise("/home");
$httpProvider.interceptors.push(['$rootScope', '$q', '$location', '$timeout',
function ($rootScope, $q, $location, $timeout) {
return {
'request': function (config) {
config.headers['X-Requested-With'] = 'XMLHttpRequest';
return config || $q.when(config);
},
'requestError': function (rejection) {
return rejection;
},
'response': function (response) {
return response || $q.when(response);
},
'responseError': function (response) {
console.log('responseError:' + response);
if (response.status === 401 || response.status === 403) {
$timeout(function () {
window.location = "/login";
//也可弹出对话框提示
}, 3000);
return false;
}
else if (response.status === 500) {
$location.path('/500.html');
return false;
}
return $q.reject(response);
}
};
}]);
}
Fiter过滤
主要逻辑:
- 获取逻辑头String requestType = request.getHeader(“X-Requested-With”);
- 判断是否Angular请求,如果是则返回401错误码,该标识可自定义
public class SessionInterceptor implements HandlerInterceptor {
public SessionInterceptor() {
// TODO Auto-generated constructor stub
}
private String mappingURL; // 利用正则映射到不需要拦截的路径 ,如代码、常用资源信息等
private String[] excludeUrls; // 不需要拦截的路径,如登录、退出等
public void setExcludeUrls(String[] excludeUrls) {
this.excludeUrls = excludeUrls;
}
public void setMappingURL(String mappingURL) {
this.mappingURL = mappingURL;
}
/**
* 在业务处理器处理请求之前被调用 如果返回false 从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链
*
* 如果返回true 执行下一个拦截器,直到所有的拦截器都执行完毕 再执行被拦截的Controller 然后进入拦截器链,
* 从最后一个拦截器往回执行所有的postHandle() 接着再从最后一个拦截器往回执行所有的afterCompletion()
*/
@SuppressWarnings("unchecked")
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
String uri = getURI(request);
String rooturi = getRootURI(request);
RequestThreadLocal.setRequestThreadLocal(request);
// // 不在验证的范围内
if (exclude(uri)) {
return true;
}
// 用户为null跳转到登陆页面
YSysUser user = (YSysUser) request.getSession().getAttribute(SystemConstants.SESSION_USER);
if (user == null) {
String requestType = request.getHeader("X-Requested-With");
if (!StringUtils.isEmpty(requestType) && requestType.equalsIgnoreCase("XMLHttpRequest")) {
response.setHeader("sessionstatus", "timeout");
response.sendError(401, "session timeout.");
return false;
}else{
response.sendRedirect(rooturi + "/login");
return false;
}
}
//验证URL权限
}
// 在业务处理器处理请求执行完成后,生成视图之前执行的动作
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// log.info("==============执行顺序: 2、postHandle================");
}
/**
* 在DispatcherServlet完全处理完请求后被调用
* 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion()
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// log.info("==============执行顺序: 3、afterCompletion============");
}
}