首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Session 過期自動跳轉登入頁:Filter 方案完整實現(支援 AJAX 與普通請求)

     編輯:Java 相關知識

專案需求:Session 失效後,普通請求重導向至登入頁;AJAX 請求回傳特定標頭,由前端統一攔截彈窗並跳轉。嘗試 HttpSessionListener 無法實現頁面跳轉,最終採用 Filter 方案。

1. web.xml 配置 Filter

<filter>
    <filter-name>sessionFilter</filter-name>
    <filter-class>com.example.filter.SessionFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>sessionFilter</filter-name>
    <url-pattern>/actions/*</url-pattern> <!-- 僅攔截業務路徑 -->
</filter-mapping>

2. SessionFilter 核心代碼

public class SessionFilter implements Filter {

    private static final String LOGIN_FLAG = "LOGIN_SUCCESS";
    private static final String LOGIN_URL = "/admin/login.jsp";

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        HttpSession session = request.getSession(false); // 不自動建立

        String requestURI = request.getRequestURI();
        String path = requestURI.substring(requestURI.lastIndexOf("/"));

        // 僅攔截 .action 結尾的業務請求
        if (path.endsWith(".action") && (session == null || session.getAttribute(LOGIN_FLAG) == null)) {

            // 判斷是否 AJAX 請求
            String requestedWith = request.getHeader("X-Requested-With");
            boolean isAjax = "XMLHttpRequest".equalsIgnoreCase(requestedWith);

            String loginPath = request.getContextPath() + LOGIN_URL;

            if (isAjax) {
                // AJAX:回傳自定標頭,不輸出頁面
                response.addHeader("sessionstatus", "timeOut");
                response.addHeader("loginPath", loginPath);
                chain.doFilter(request, response); // 讓後續流程結束,避免進一步處理
            } else {
                // 普通請求:輸出 JS 彈窗並重導向頂層視窗
                response.setContentType("text/html;charset=UTF-8");
                PrintWriter out = response.getWriter();
                out.println("<script>alert('會話已過期,請重新登入'); window.top.location.href='" + loginPath + "';</script>");
                out.flush();
            }
            return;
        }

        chain.doFilter(request, response);
    }

    @Override public void init(FilterConfig config) {}
    @Override public void destroy() {}
}

3. 前端 AJAX 全域攔截

jQuery 版

$(document).ajaxComplete(function(event, xhr, settings) {
    if (xhr.getResponseHeader("sessionstatus") === "timeOut") {
        var loginPath = xhr.getResponseHeader("loginPath");
        if (loginPath) {
            alert("會話已過期,請重新登入");
            window.location.replace(loginPath);
        } else {
            alert("請求超時,請重新登入");
        }
    }
});

ExtJS 版

Ext.Ajax.on('requestcomplete', function(conn, response, options) {
    if (response.getResponseHeader("sessionstatus") === "timeout") {
        var loginPath = response.getResponseHeader("loginPath");
        if (loginPath) {
            alert("會話已過期,請重新登入");
            window.top.location.href = loginPath;
        } else {
            alert("請求超時,請重新登入");
        }
    }
});

特定 AJAX 請求跳過全域攔截

$.ajax({
    url: "test.html",
    global: false // 不觸發 ajaxComplete 等全域事件
});

關鍵設計點

  1. Session 取得策略: 使用 getSession(false) 避免 Filter 本身創建新 Session 導致判斷失效。
  2. 請求區分: 依 X-Requested-With: XMLHttpRequest 標頭識別 AJAX(jQuery/ExtJS 預設發送)。
  3. 回應協議: 自定標頭 sessionstatus=timeOut + loginPath,前端零耦合業務代碼。
  4. 普通請求處理: 直接輸出 <script> 強制頂層視窗跳轉,適用於 iframe 嵌套場景。

此方案已在多個專案穩定運行,兼容傳統表單提交與現代 AJAX 架構。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved