概要
背景
在开发过程中完成session共享时测试session中断过期页面响应而遇到了问题。技术使用
springboot+redis+shiro+静态html分离式前端
解决办法
首先要弄懂一个问题,为什么服务端写了重定向,前端页面没有去跳转?并且重定向里的请求location也指向清楚了。
因为ajax请求里涉及返回两种类型,一种是返回json,一种是返回页面内容,如果纯粹的返回内容的话就走304,页面去读缓存了,然后重定向在阻塞,导致页面没有刷新,当手工刷新才加载304要显示的页面内容。
手动再现一下之前的场景,下图为综合过程结果:
- ajax请求,发送/findList查询到后台服务端
$.ajax({
url:serverUrl+'/departments/findList',
type:'post',
data: row,
async:false,
success: function (data) {
if (data.success) {
$.messager.alert("错误");
}
}
});
接着服务端拦截器处理请求,博主使用的shiro管理会话和权限,所以会拦截请求做对应的的校验,若校验失败(本例以session失效演示),则进入filter设置好的重定向目录/sessionFailure
由于session失效或权限不足等情况引起的框架(或用户自己使用redirect之类的跳转)重定向,会直接在ServletResponse里设置head的location值,告诉前端请求,向这个新地址重新请求,那么之前请求的/findList,压根就没有到具体业务运行的代码上就已经去执行新的请求了/sessionFailure,如最开始的第一张过程图
之后我们在请求/sessionFailure中做对应业务处理,有2种返回方式:页面返回和json返回。从现在的开发来看,如果使用的页面返回,那么是适用于伪前后端分离和不分离的项目架构,这里只需要使用脚本语言即可,会自动帮你处理好response的页面展示;
- 从前后端分离式开发看,服务端是不做页面返回的,所以统一以json返回,前端自行处理返回的状态,根据状态自行处理静态页面的跳转,但现在前端大多都采用框架结构了,并且前端语言和库更加丰富,实际上前端也在做mvc、mvv开发,具体使用什么语言博主不做说明(因为只会vue2),博主做这个文章是建立在纯静态html+jquery的前端上实现的,也就是说会用ajax+jquery做到全局处理的事情
/**
* 会话过期 -- 用户处于未登录状态
* @param response
*/
@RequestMapping("/sessionFailure")
public ModelAndView sessionFailure(HttpSession session, HttpServletResponse response) {
System.out.println(SecurityUtils.getSubject().getSession().getAttribute(SessionStatus.STATUS));
if (null == getCurrentUser()) {
response.setHeader(SessionStatus.STATUS, SessionStatus.EXPIRED);
}
//方法1:返回页面内容跳转
ModelAndView model = new ModelAndView();
model.addObject("result", Result.result(1, false, StatusCode.LOGINOUT, ResultType.LOGINOUT));
//model.setViewName("forward:/user/login.html");
model.setViewName("redirect:/user/login.html");
//方法2:ajax-json返回,由前端捕获自行操作代码
Map<String, Object> result = new HashMap<String, Object>();
result.put("sessionStatus", "expired");
result.put("message", ResultType.LOGINOUT);
result.put("code", StatusCode.LOGINOUT);
//方法2包装
doResult(response, flag, StatusCode.DEFAULT, null, flag ? "通过" : "失败");
return model;
}
- 如果你使用的是跟博主类似的环境,并且是前后端分离式开发,那么建议使用上述的方法2,自己包装返回json,不要返回页面。创建一个js,加入如下引用,在index页面引入一下
$.ajaxSetup({
asycn: false,
xhrFields: {
withCredentials: true
},
error: function (XMLHttpRequest, textStatus, errorThrown){
if(XMLHttpRequest.status==403){
alert('您没有权限访问此资源或进行此操作');
return false;
}
},
contentType:"application/x-www-form-urlencoded;charset=utf-8",
complete: function (XMLHttpRequest,textStatus) {
debugger;
//通过XMLHttpRequest取得响应头,sessionstatus
var sessionstatus = XMLHttpRequest.getResponseHeader("sessionStatus");
//通过XMLHttpRequest取得返回的json
var json = XMLHttpRequest.responseJSON;
//通过XMLHttpRequest取得返回的text
var text = XMLHttpRequest.responseText;
}
});
不懂ajaxSetup可以看一下,ajaxSetup是一个类似前端ajax父级的东西,也就是说如果有了这个,你的页面里写的其他$.ajax就是它的子集,会默认带上ajaxSetup上设置的属性,另外ajaxSetup的一些方法如dataFilter、complete、success都是
在你的ajax请求时会去执行的方法(至于先执行还是后执行,不是本文讨论的方法,后续做详细介绍)。这里博主是利用的complete监听所有的ajax请求,在请求执行完成后进入方法,执行后续动作,若服务端在重定向执行我上述的/sessionFailure请求时返回了json,那么就使用XMLHttpRequest.responseText去读取服务端返回的json内容,判断你返回的状态,上面代码服务端的例子是用的sessionStatus,所以现在前端例子上也是用这个办法,博主列举了可行的三种方式,任选。
总结
有问题留言交流,博主比较懒,草稿箱里有四十多篇没写完的博客,只能趁现在工作不忙,一段时间一篇慢慢还原环境去补充了,累!!!!