jQuery ajax 302跨域


一、ajax 302


ajax用於異步獲取服務器數據,但是某天有這么一個使用場景:

> 基於安全考慮,登錄的用戶的信息失效時,系統的所有ajax接口都由服務器直接重定向到系統的登錄頁面,此時登錄頁面與系統屬於同一個域;

於是否,使用ajaxComplete的方法為系統所有ajax統一設置請求完成后的回調,判斷其http的status code是否為302,類似於下面代碼:

$(document).ajaxComplete(function(e, xhr, settings){
    var _location;
    console.log(xhr);
    if(xhr.status === 302){
        _location = xhr.getResponseHeader("Location");
        if(_location) {
            location.assign(_location);
        }
    }
});

//獲取數據的接口
$.ajax({
    url: "/api/fetch.html"
}).always(function(ret){
     console.log(ret);
});

可是測試結果顯示,ajax的回調在重定向之后死活沒有執行,直至獲取重定向后的請求才會執行ajax的回調,也就是說重定向后的內容作為ajax的接口內容來響應。此時可以看到瀏覽器控制台輸出的ret內容不是json字符串,實際上為系統重定向到登錄頁面的html字符串。


為什么會出現這樣的結果呢?

在stackoverflow上可以找到討論的答案

> You can't handle redirects with XHR callbacks because the browser takes care of them automatically. You will only get back what at the redirected location.

也就是說,重定向是由瀏覽器自動透明的完成的。所以服務器將302響應發給瀏覽器時,瀏覽器並不是直接處理ajax的回調,而是先執行302重定向。這就是上面例子中為什么獲取不到xhr.status為302的值。

一個ajax請求的重定向大致流程是這樣的:

ajax --> browser --> server --> 302 --> browser(redirect) --> server --> browser --> ajax callback

注意,上面ajax獲取不到xhr的status是有一個前提:即,服務器為response設置了*Location* header

因為,瀏覽器在發現Location的header時就會自動跳轉到Location所指定的URL地址,類似於用js來進行重定向;不過這個重定向只有瀏覽器知道。

所以,在ajax接口返回302時,而沒有設置Location的header時,這個xhr的status值還是能獲取到的,下圖是在瀏覽器控制台測試的結果:

可以看到服務器給response的header添加了Location1的header,瀏覽器並不認識,所以不會重定向,此時或可以獲取xhr的status為302

二、ajax 302跨域


隨着公司業務的發展新的情況出現了,公司要將登錄認證統一到某台公共的服務器上,這時,失效的用戶在ajax獲取數據時狀態失效而被重定向到登錄頁面;由於當前系統與登錄頁面不同域,而XHR不允許跨域訪問數據,所以ajax的302也存在跨域問題。(不像頁面之間重定向不存在這個問題,你可以訪問當前系統的某個頁面,服務可以重定向到www.baidu.com而不會有跨域問題)。

這時,由於存在跨域,瀏覽器不會進行重定向;但是能否通過上面的代碼來用JavaScript進行重定向呢?

抱歉,同樣不可以;這時通過ajaxComplete方法獲取到的xhr的status值,發現其值為0,Location的header為null;所以這種辦法行不通。更可取的方法可以是這樣:

首先不要在服務器端進行重定向;然后通過接口的形式或者在response添加一個自定義header來區分重定向信息;最后由JavaScript來進行重定向

三、xhr status為0的問題


翻看W3C文檔,發現xhr的status值由以下三個步驟來決定:

The status attribute must return the result of running these steps:

  1.  If the state is UNSENT or OPENED, return 0.

  2.  If the error flag is set, return 0.

  3.  Return the HTTP status code.

第二條的error flag:The error flag indicates some type of network error or fetch termination. It is initially unset.

通過上面得知:

在調用xhr的open方法還沒有調用send方法,或者xhr出錯了(如跨域就會發生網絡錯誤)都會導致xhr state為0的情況

最常見的兩種xhr status為0的情況:

  • ajax發送后還沒有得到響應前立即刷新瀏覽器,這時ajax就會被瀏覽器給丟棄了,會返回status code為0;這主要發生在form表單的提交用ajax來提交,而沒有阻止表單提交的默認行為,導致頁面刷新,這時ajax發出了,但頁面刷新; 其實ajax能得到xhr的status只不過值為0;

  • xhr跨域,包括異步請求跨域和302跨域的情況,這時會出現xhr status為0的情況

參考文獻


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM