Http請求狀態碼302,已得到html頁面但未跳轉?HttpServletRequest轉發/HttpServletResponse重定向後,前端頁面未跳轉?Ajax怎麼處理頁面跳轉?

論斷

出現此類錯誤,伺服器端出現問題的可能性不大,大概率是前端問題。

問題概述

事情是這樣的,我在用Java開發後端。前端頁面使用jQuery庫的 $.getJSON() 方法發送了一個Ajax請求

添加過濾器跳轉之前前端效果正常。

但是當我在後端加上了一個判斷用戶是否已經登錄的Filter過濾器時,出現了問題!

過濾器功能很簡單:

  • 用戶已經登錄:請求順利通過過濾器;
  • 用戶還沒有登錄:過濾器通過請求或響應響應的對象進行跳轉。

增加過濾器後的結果:

  • 登錄狀態:前端頁面依然正常顯示數據。
  • 非登錄狀態:頁面既沒有顯示數據也沒有跳轉!
    • 此時打開瀏覽器後台查看:
      • 請求的狀態碼為302
      • 瀏覽器後台已獲取到需要跳轉的頁面,但是前端當前頁面卻沒有改變

出錯圖(1)👇

出錯圖(2)👇

問題分析

排除問題

  • 非後端的問題:
    1. 以前實多次使用過濾器跳轉並沒有出現問題
    2. 前端確實收到了跳轉頁面,只不過沒有顯示
  • 通過測試排除一些其他問題:
    1. 具體排除了什麼不記得了

逼近真相

  • 排除了後端問題後,我開始在網上搜索前端問題的解決方案(我對前端不熟悉)。
  • 逐漸的我將問題鎖定在Ajax請求和$.getJSON()方法上。
  • 看到網上說Ajax不適合做跳轉,並提供的Ajax實現跳轉的方法,然而並不適合我的程式碼。
  • 又看到了有人說,可以在請求方法後面加上window.location='/'實現跳轉,我試了,這種跳轉是無差別的跳轉。也就是說在登錄狀態下成功返回JSON數據是也是會跳轉的!這顯然不是我想要的結果。

到這裡,答案已經十分接近了。也就是在返回JSON的時候不跳轉,返回html的時候跳轉。

但是當我在查怎麼知道Ajax返回結果的時候卡住,沒有找到滿意的答案。

正在愁呢,突然就想起一件事情:也許$.getJSON()方法是是有返回值的!於是我嘗試接收了這個返回值,並用consle.log()在控制台記錄這個對象。果然,出現了一個包含很多資訊的對象!

最終解決

我分別測試了,登錄狀態和未登錄狀態下$.getJSON()方法的返回對象。在仔細對比後發現了其中的不同!

我發現這個對象有一個屬性statusText:

  • ajax請求得到了正確響應時:即得到了JSON對象,statusText屬性的值為”success”;

  • ajax請求得到了錯誤響應時:即沒有得到JSON對象,而是得到一個html,statusText屬性的值為”parsererror”

    parser error : 分析器錯誤

「神秘對象」截圖👇

解決方案:很簡單,只要獲得「神秘對象」並判斷statusText屬性值區別處理!

程式碼:不過彩筆的我還是因為不熟悉JavaScript,被JavaScript的函數執行順序、變數作用域折磨了半天,最終狼狽的解決了問題。

  • 前端頁面Ajax請求部分程式碼
<script>
    $(function () {
        //定義一個執行Ajax請求並能獲取Ajax函數返回值的函數
        let ajaxFunction = function () {
            //發起Ajax請求,並把返回值直接return出去
            return $.getJSON("/wx/expressList.do", null, function (data) {
                //如果沒有返回JSON對象,就不會執行回調函數
                //回調函數具體程式碼,與問題無關
                //... ...
            });
        }
        //執行上面定義的函數,並判斷Ajax響應是否為json
        if (ajaxFunction().statusText !== 'success'){
            //響應結果不是json,在本例中不是json那就只能時html了!
            window.location = '/';
            //或者使用下面的語句,效果完全相同
            //window.location = '/wx/expressList.do';
        }
    })
</script>
  • 後端過濾器程式碼(不重要)
@WebFilter({"/wx/expressList.do", "其他請求"})
public class UserAccessFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        //判斷用戶是否已經登錄的實現程式碼
        boolean isLoggedIn = ... ;
        //到這兒是判斷用戶是否已經
        if (isLoggedIn) {
            //用戶已登錄,請求通過
            filterChain.doFilter(req, resp);
        } else {
            //跳轉(重定向)至登錄頁面
            resp.sendRedirect("/login.html");//這裡使用req跳轉(轉發)也可以
        }
    }

    @Override
    public void destroy() {}

還沒解決?評論區見~