使用场景
在Spring中使用拦截器时,有时候会拦截ajax请求,此时我们可能会根据权限等因素对ajax数据进行个性化返回,比如跳转到其他页面或者进行alert提示等,从response对象中是无法直接进行这些操作的,需经过前端页面的配合才行。
整体思路
- 前端要使用了 jQuery 才行,因为要用到 jQuery 的 $.ajaxSetup 。
- 前端需要对ajax进行个性化返回处理的页面添加ajax的全局设置 $.ajaxSetup ,以便在ajax动作的某一阶段介入来完成一些工作。
- 后端需要识别本次请求是否是ajax请求,如果是ajax请求,则进行定制化返回。(通过在response的header中添加属性可实现)
- 前端页面发起ajax请求,后端处理并返回给前端,前端会执行 $.ajaxSetup 中配置好的行为。
我们的整体思路
- 在需要对ajax进行个性化返回处理的页面添加$.ajaxSetup并设定complete行为。
- 在$.ajaxSetup的complete行为中使用我们自定义的header属性来完成一系列工作。
- 在后端进行请求类型的区分判断,如果是ajax请求,那么就在response的header中添加我们自定义的header属性并返回到前端,让前端的$.ajaxSetup的complete行为来处理。
实现代码
Alert版
- 在需要进行ajax返回定制化的页面设置$.ajaxSetup(更推荐将此代码单提出一个js文件以便多页面共享)
$.ajaxSetup({
contentType: "application/x-www-form-urlencoded;charset=utf-8",
complete: function (XMLHttpRequest, textStatus) {
//通过XMLHttpRequest取得响应头,sessionstatus,
var sessionstatus = XMLHttpRequest.getResponseHeader("sessionStatus");
if (sessionstatus == "AlertMessage") {
var alertMessageInfo = decodeURI(XMLHttpRequest.getResponseHeader("alertMessageInfo"));
window.alert(alertMessageInfo);
}
}
});
- $.ajaxSetup的主要功能为给所有的ajax请求进行统一设置
- 我们为ajax请求统一设置了一个 complete 回调函数,complete 回调函数会在ajax完成后被调用,不论是error还是ok
- 在complete回调函数中,我们拿到后端写好的两个请求头属性sessionStatus和alertMessageInfo来进行个性化处理
- 本例中是通过window.alert来进行弹框提示,因为提示内容是中文,所以需要用decodeURI来进行中文解码
- 后端拦截器识别请求是否是ajax请求
public class LimitInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
if(需要拦截) {
requestNeedLimit(response, request);
}
return true;
}
/**
* 请求被拦截时的友情提示
*
* @param response
* @param request
* @throws IOException
*/
private void requestNeedLimit(HttpServletResponse response, HttpServletRequest request) throws IOException {
// 是ajax请求
if (StringUtils.equals("XMLHttpRequest", request.getHeader("X-Requested-With"))) {
// ajax请求
response.setContentType("text/html");
response.setHeader("sessionStatus", "AlertMessage");
response.setHeader("alertMessageInfo", URLEncoder.encode("您的访问过于频繁,已被锁定,请等待解锁!", "UTF-8"));
} else {
// 不是ajax请求
response.setContentType("text/html; charset=UTF-8");
response.getWriter().print("<html><body><script type='text/javascript'>alert('您的访问过于频繁,已被锁定,请等待解锁!');</script></body></html>");
response.getWriter().close();
response.flushBuffer();
}
}
// 其他代码
}
- 如果是ajax请求,那么我们会为response设定两个自定的属性sessionStatus和alertMessageInfo
- 因为alertMessageInfo是中文,所以需要URLEncoder.encode来进行中文编码
- 如果不是ajax请求那么我们也会通过流的方式弹出alert进行提示
跳转版(可以跳转到页面或Controller)
- 在需要进行ajax返回定制化的页面设置$.ajaxSetup(更推荐将此代码单提出一个js文件以便多页面共享)
$.ajaxSetup( {
//设置ajax请求结束后的执行动作
complete :
function(XMLHttpRequest, textStatus) {
// 通过XMLHttpRequest取得响应头,sessionstatus
var sessionstatus = XMLHttpRequest.getResponseHeader("sessionstatus");
if (sessionstatus == "needRedirect") {
var win = window;
while (win != win.top){
win = win.top;
}
win.location.href= XMLHttpRequest.getResponseHeader("CONTEXTPATH");
}
}
});
- $.ajaxSetup的主要功能为给所有的ajax请求进行统一设置
- 我们为ajax请求统一设置了一个 complete 回调函数,complete 回调函数会在ajax完成后被调用,不论是error还是ok
- 在complete回调函数中,我们拿到后端写好的两个请求头属性sessionStatus和CONTEXTPATH(请求跳转路径,可以是jsp也可以是Controller的mapping路径)来进行个性化处理
- 通过win.location.href来进行页面跳转
- 后端拦截器识别请求是否是ajax请求
public class LimitInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
if(需要拦截) {
requestNeedLimit(response, request);
}
return true;
}
/**
* 请求被拦截时的友情提示
*
* @param response
* @param request
* @throws IOException
*/
private void requestNeedLimit(HttpServletResponse response, HttpServletRequest request) throws IOException {
// 重定向用的服务基本路径
String basePath = request.getScheme() + "://"+ request.getServerName() + ":" + request.getServerPort()+ request.getContextPath() + "/";
// 是ajax请求
if (StringUtils.equals("XMLHttpRequest", request.getHeader("X-Requested-With"))) {
// ajax请求
// 设定状态为超时
response.setHeader("sessionstatus", "needRedirect");
// 需要跳转的页面地址(请求跳转路径,可以是jsp也可以是Controller)
response.setHeader("CONTEXTPATH", basePath+"index.jsp");
//403 禁止
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
} else {
// 不是ajax请求
response.setContentType("text/html; charset=UTF-8");
response.getWriter().print("<html><body><script type='text/javascript'>alert('您的访问过于频繁,已被锁定,请等待解锁!');</script></body></html>");
response.getWriter().close();
response.flushBuffer();
}
}
// 其他代码
}
- 如果是ajax请求,那么我们会为response设定两个自定的属性sessionStatus和CONTEXTPATH***(请求跳转路径,可以是jsp也可以是Controller)***
- 如果不是ajax请求那么我们也会通过流的方式弹出alert进行提示
对layui请求的特殊处理
因为layui的ajax请求使用的其实是layui自身内置的JQuery,和普通的ajax请求不能兼容处理,需要额外使用layui的JQuery再设定一次$.ajaxSetup才行,示例代码如下(更推荐将此代码单提出一个js文件以便多页面共享):
if(typeof(layui)!="undefined") {
setAjaxSetUp(layui.jquery);
}
if(typeof(jQuery)!="undefined") {
setAjaxSetUp(jQuery);
}
function setAjaxSetUp(jQueryObject) {
if(typeof(jQueryObject)!="undefined") {
jQueryObject.ajaxSetup({
contentType: "application/x-www-form-urlencoded;charset=utf-8",
complete: function (XMLHttpRequest, textStatus) {
//通过XMLHttpRequest取得响应头,sessionstatus,
var sessionstatus = XMLHttpRequest.getResponseHeader("sessionStatus");
if (sessionstatus == "AlertMessage") {
var alertMessageInfo = decodeURI(XMLHttpRequest.getResponseHeader("alertMessageInfo"));
window.alert(alertMessageInfo);
}
}
});
}
}
后端拦截器中对于前端请求的处理,和之前一样,没有区别:
public class LimitInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
if(需要拦截) {
requestNeedLimit(response, request);
}
return true;
}
/**
* 请求被拦截时的友情提示
*
* @param response
* @param request
* @throws IOException
*/
private void requestNeedLimit(HttpServletResponse response, HttpServletRequest request) throws IOException {
// 是ajax请求
if (StringUtils.equals("XMLHttpRequest", request.getHeader("X-Requested-With"))) {
// ajax请求
response.setContentType("text/html");
response.setHeader("sessionStatus", "AlertMessage");
response.setHeader("alertMessageInfo", URLEncoder.encode("您的访问过于频繁,已被锁定,请等待解锁!", "UTF-8"));
} else {
// 不是ajax请求
response.setContentType("text/html; charset=UTF-8");
response.getWriter().print("<html><body><script type='text/javascript'>alert('您的访问过于频繁,已被锁定,请等待解锁!');</script></body></html>");
response.getWriter().close();
response.flushBuffer();
}
}
// 其他代码
}