You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 00:05:30