$.ajax 请求 拦截器 重定向 无效 解决办法

本文介绍如何在SpringBoot项目中利用拦截器实现AJAX请求下的Session超时重定向功能。通过自定义拦截器并针对AJAX请求进行特殊处理,确保在Session过期时能够正确地跳转至登录页面。

在ajax 异步请求下 拦截器过滤器中使用 重定向 页面响应无效

我这里用的是springboot框架,用拦截器实现 对请求的拦截 ,session超时直接跳转到login.html页面。

后台代码:

@Override
    public void addInterceptors(InterceptorRegistry registry)
    {
    //加载自定义拦截器(登录请求和退出请求放行)
        registry.addInterceptor(new DemoIntercept()).addPathPatterns("/**").excludePathPatterns("/loginController","/logout");
    }


/**
*自定义拦截器
**/
public class DemoIntercept implements HandlerInterceptor
{

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object arg2, Exception arg3)
            throws Exception
    {
        logger.info("afterCompletion:{}", request.getRequestURI());
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView arg3)
            throws Exception
    {
        logger.info("postHandle:{}", request.getRequestURI());
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception
    {
        //获取session
        HttpSession session = request.getSession();
        Object username = session.getAttribute("username");
        //用户如果为null 则 重定向到 login页面 ,否则放行
        if(null == username)
        {
            //重定向到login.html
             redirect(request, response); 
             return false;
        }
        return true;
    }


      //对于请求是ajax请求重定向问题的处理方法
    public void redirect(HttpServletRequest request, HttpServletResponse response) throws IOException{
        //获取当前请求的路径
        String basePath = request.getScheme() + "://" + request.getServerName() + ":"  + request.getServerPort()+request.getContextPath();
        //如果request.getHeader("X-Requested-With") 返回的是"XMLHttpRequest"说明就是ajax请求,需要特殊处理 否则直接重定向就可以了
        if("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))){
            //告诉ajax我是重定向
            response.setHeader("REDIRECT", "REDIRECT");
            //告诉ajax我重定向的路径
            response.setHeader("CONTENTPATH", basePath+"/login.html");
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        }else{
            response.sendRedirect(basePath + "/login.html");
        }
    }
}

前台代码

//这里给所有ajax请求添加一个complete函数
$.ajaxSetup({
            complete : function(xhr, status) {
                //拦截器实现超时跳转到登录页面
                // 通过xhr取得响应头
                var REDIRECT = xhr.getResponseHeader("REDIRECT");
                //如果响应头中包含 REDIRECT 则说明是拦截器返回的
                if (REDIRECT == "REDIRECT")
                {
                    var win = window;
                    while (win != win.top)
                    {
                        win = win.top;
                    }
                    //重新跳转到 login.html 
                    win.location.href = xhr.getResponseHeader("CONTEXTPATH");
                }
            }
        });

这里实现的原理也就是,后台在ajax请求头上打上标记 (REDIRECT ),标记(REDIRECT )这个请求要重定向,而前台接受到响应后 根据标记(REDIRECT )判断这个响应头是否需要 重定向 如果需要则 则获取重定向地址 就可以了

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Smart-SSO-Demo-H5</title> </head> <body> <h2>Smart-SSO-Demo-H5</h2> <br /><b>用户名</b>:<span id="_username"></span><br /> <br /><b>用户已分配的菜单</b>:<span id="_userMenus"></span> <br /><b>用户已分配的权限</b>:<span id="_userPermissions"></span> <br /><a href="javascript:goSSOLogoutUrl()">单点退出</a> </body> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script>window.jQuery || alert('jQuery.js未加载成功,请检查网络或更换CDN')</script> <script type="text/javascript"> // 当前应用(smart-sso-demo-h5)后端服务地址 var BASE_URL = "http://127.0.0.1:8082"; // 客户端ID(保持与smart.sso.client-id配置一致,用于多个客户端应用在同域部署下的数据隔离) var CLIENT_ID = "1002"; // token名称前缀(保持与smart.sso.token-name-prefix配置一致,如果没有自定义则默认"smart-sso-token-") var TOKEN_NAME_PREFIX = "smart-sso-token-"; $(function () { if (validateLogin()) { getUserinfo(); } }) // 校验是否需要跳转到SSO认证中心 function validateLogin() { var accessToken = localStorage.getItem("accessToken" + CLIENT_ID); if (accessToken) { return true; } var code = getParam('code'); if (code && getAccessToken(code)) { removeCodeParamAndRedirect(); return true; } goSSOLoginUrl(); return false; } // 获取用户信息 function getUserinfo() { smart.ajax('GET', BASE_URL + "/userinfo", {}, function (res) { var userinfo = res.data; // 用户名 $("#_username").html(userinfo.username); // 用户已分配的菜单 var userMenus = ''; userinfo.userMenus.forEach(function (menu) { userMenus += '<li>' + menu + '</li>'; }); $('#_userMenus').html(userMenus); // 用户已分配的权限 var userPermissions = ''; userinfo.userPermissions.forEach(function (permission) { userPermissions += '<li>' + permission + '</li>'; }); $('#_userPermissions').html(userPermissions); }); } // 重定向至认证中心 function goSSOLoginUrl() { $.getJSON(BASE_URL + '/auth/login_url?redirectUri=' + location.href, function (res) { window.location.href = res.data; }) } // 重定向至服务端退出地址 function goSSOLogoutUrl() { $.getJSON(BASE_URL + '/auth/logout_url?redirectUri=' + location.href, function (res) { window.location.href = res.data; }) } // 获取accessToken function getAccessToken(code) { var bool = false; $.ajax({ url: BASE_URL + "/auth/access-token?code=" + code, type: 'GET', async: false, dataType: 'json', success: function (res) { if (res.code == 1) { localStorage.setItem("accessToken" + CLIENT_ID, res.data.accessToken); localStorage.setItem("refreshToken" + CLIENT_ID, res.data.refreshToken); bool = true; } } }); return bool; } // 获取refreshToken function getRefreshToken() { var bool = false; $.ajax({ url: BASE_URL + "/auth/refresh-token?refreshToken=" + localStorage.getItem("refreshToken" + CLIENT_ID), type: 'GET', async: false, dataType: 'json', success: function (res) { if (res.code == 1) { localStorage.setItem("accessToken" + CLIENT_ID, res.data.accessToken); localStorage.setItem("refreshToken" + CLIENT_ID, res.data.refreshToken); bool = true; } } }); return bool; } // 从url中获取指定名称的参数值 function getParam(name) { var query = window.location.search.substring(1); var vars = query.split("&"); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split("="); if (pair[0] == name) { return pair[1]; } } return null; } // 重定向方式去除地址栏中的code参数 function removeCodeParamAndRedirect() { var url = new URL(window.location.href); url.searchParams.delete('code'); window.location.href = url.toString(); } </script> <script type="text/javascript"> var smart = {}; // 为业务请求封装Ajax方法,请求头自动附带token,请求返回处理token刷新和失效跳转等逻辑 smart.ajax = function (method, url, data, successFn) { $.ajax({ type: method, url: url, data: data, dataType: 'json', headers: { // 传递调用凭证 [TOKEN_NAME_PREFIX + CLIENT_ID]: localStorage.getItem("accessToken" + CLIENT_ID), // 跨域请求需自行设置X-Requested-With参数,Ajax仅在非跨域请求默认携带 'X-Requested-With': 'XMLHttpRequest' }, success: function (res) { // 响应成功 if (res.code == 1) { successFn(res); } // 后端登录失效,需要清理前端缓存,并跳转至认证中心 else if (res.code == 10) { localStorage.clear(); goSSOLoginUrl(); } /** * accessToken已过期,refreshToken已过期,客户端需要调用refreshToken刷新accessToken * 1、如果refreshToken成功,之前因为accessToken过期请求失败的接口再发起一遍 * 2、否则,跳转至认证中心 */ else if (res.code == 15) { if (getRefreshToken()) { smart.ajax(method, url, data, successFn); } else { goSSOLoginUrl(); } } // 其它异常,弹出提示 else { alert(res.message); } }, error: function (xhr, type, errorThrown) { alert(JSON.stringify(xhr)); } }); } </script> </html> 前后端分离场景 集成到若依vue3框架
最新发布
10-30
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值