首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

SSH 整合項目中 Session 過期跳轉登錄頁:Filter 方案與 JSON 請求處理最佳實踐

     編輯:程式設計疑難解答

場景痛點

使用 Struts2 + Spring + Hibernate (SSH) + EasyUI,AJAX 請求返回 JSON。Session 過期時,後端拋異常或返回視圖,前端無法跳轉登錄頁(因非整頁請求,JS 無法處理重定向響應)。

核心方案:Filter 攔截 + 約定式響應碼

1. 登錄狀態檢查 Filter

public class SessionFilter implements Filter {
    private static final String[] EXCLUDE_PATHS = {"/login", "/css/", "/js/", "/images/", "/error"};

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) 
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        String uri = request.getRequestURI();
        String ctx = request.getContextPath();

        // 靜態資源、登錄頁放行
        if (Arrays.stream(EXCLUDE_PATHS).anyMatch(p -> uri.startsWith(ctx + p))) {
            chain.doFilter(request, response);
            return;
        }

        HttpSession session = request.getSession(false);
        boolean loggedIn = (session != null && session.getAttribute("user") != null);

        // 判斷是否 AJAX 請求
        boolean isAjax = "XMLHttpRequest".equals(request.getHeader("X-Requested-With")) 
                      || "application/json".equals(request.getHeader("Accept"));

        if (!loggedIn) {
            if (isAjax) {
                // 返回 401 + JSON,前端統一攔截跳轉
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write("{\"code\":401,\"msg\":\"Session expired, please login\"}");
            } else {
                // 整頁請求直接重定向
                response.sendRedirect(ctx + "/login.jsp");
            }
            return;
        }
        chain.doFilter(request, response);
    }
}

2. web.xml 配置 Filter(放在最前)

<filter>
    <filter-name>sessionFilter</filter-name>
    <filter-class>com.yourpkg.SessionFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>sessionFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- Session 超時配置(分鐘) -->
<session-config>
    <session-timeout>30</session-timeout>
</session-config>

3. 前端 JS 統一攔截(jQuery 示例)

$.ajaxSetup({
    complete: function(xhr) {
        if (xhr.status === 401) {
            // 彈窗提示並跳轉
            $.messager.alert('提示', '登錄已過期,請重新登錄', 'info', function() {
                window.top.location.href = '${pageContext.request.contextPath}/login.jsp';
            });
        }
    }
});

// EasyUI datagrid/form/ajax 統一錯誤處理
$(document).ajaxError(function(event, xhr) {
    if (xhr.status === 401) { /* 同上 */ }
});

關鍵點總結

  • Filter 而非 Interceptor:Filter 在 Servlet 容器層面,能攔截所有請求(含靜態資源、Struts2 Action、Spring MVC Controller),Interceptor 僅攔截進入 Action/Controller 的請求。
  • 約定 401 狀態碼:RESTful 標準,前端易識別,不污染業務代碼。
  • 區分 AJAX/整頁:AJAX 返回 JSON,整頁重定向,兼容傳統表單提交。
  • 前端統一攔截:$.ajaxSetup 或 axios.interceptors 一處配置,全局生效。

進階:Token 刷新機制

若不想強制跳轉,可在 Filter 中檢測 Refresh-Token Header,調用 Service 刷新 Access Token,返回新 Token 給前端(Header 或 Body),前端自動重試原請求。適合 App/SPA 長連接場景。

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