如何在JavaEE Filter中实现AJAX请求时的非AJAX页面重定向?
问题描述
我正在为采用外部认证提供商的应用创建Web Filter,要求在无Cookie、Cookie内令牌无效或过期时重定向到登录页。非AJAX请求下功能正常,但AJAX请求时,Filter会向登录页URL发起AJAX请求,而非触发浏览器以非AJAX方式重定向到该页面。我需要让Filter能引导用户直接跳转到登录页(非AJAX请求),方便用户输入凭据。
当前代码
@WebFilter(urlPatterns = "/*") public class SecurrityFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; String requestURI = httpRequest.getRequestURI(); if (requestURI.matches(".*(css|jpg|png|gif|js)")) { chain.doFilter(request, response); return; } Cookie[] cookies = httpRequest.getCookies(); boolean cookieExists = false; String cookieValue = null; if (cookies != null) { for (Cookie cookie : cookies) { if ("miCookie".equals(cookie.getName())) { cookieExists = true; cookieValue = cookie.getValue(); break; } } } if (!cookieExists || !isActiveSession(cookieValue)) { if (isAjaxRequest(httpRequest)) { //Redirect to http://localhost:8081/login/database using GET method and not using an ajax request return; } else { httpResponse.sendRedirect("http://localhost:8081/login/database"); return; } } chain.doFilter(request, response); } }
解决方案
AJAX请求由JS发起异步调用,浏览器不会自动处理3xx重定向跳转(只会跟随AJAX请求的重定向)。要实现用户跳转到登录页,需要后端返回标识状态,由前端JS触发页面跳转:
方案1:返回401状态码+登录地址响应头
修改Filter中AJAX分支的逻辑:
if (isAjaxRequest(httpRequest)) { // 返回401未授权状态码 httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 在响应头中携带登录页面地址 httpResponse.setHeader("Login-Redirect-Url", "http://localhost:8081/login/database"); return; }
然后在前端全局AJAX拦截器中监听401状态,获取响应头中的地址并跳转:
// jQuery全局拦截示例 $.ajaxSetup({ complete: function(xhr) { if (xhr.status === 401) { var loginUrl = xhr.getResponseHeader("Login-Redirect-Url"); window.location.href = loginUrl; } } });
方案2:返回JSON格式的跳转指令
如果前端更易处理JSON响应,可直接返回包含跳转地址的JSON:
if (isAjaxRequest(httpRequest)) { httpResponse.setContentType("application/json"); httpResponse.setCharacterEncoding("UTF-8"); // 输出JSON响应 httpResponse.getWriter().write("{\"redirectUrl\":\"http://localhost:8081/login/database\"}"); return; }
前端对应处理:
// Axios拦截器示例 axios.interceptors.response.use(function (response) { return response; }, function (error) { if (error.response.data && error.response.data.redirectUrl) { window.location.href = error.response.data.redirectUrl; } return Promise.reject(error); });
补充:完善isAjaxRequest方法
确保正确判断AJAX请求,通常通过请求头X-Requested-With识别:
private boolean isAjaxRequest(HttpServletRequest request) { String requestedWith = request.getHeader("X-Requested-With"); return "XMLHttpRequest".equals(requestedWith); }
内容的提问来源于stack exchange,提问作者Eduardo Roque
相关产品推荐
相关产品推荐

