jQuery ajax 302跨域

1、ajax 302


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

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

因而否,使用ajaxComplete的方法爲系統全部ajax統一設置請求完成後的回調,判斷其http的status code是否爲302,相似於下面代碼:html

$(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字符串。
***java

爲何會出現這樣的結果呢?jquery

在stackoverflow上能夠找到討論的答案ajax

> 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的值。json

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

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安全

2、ajax 302跨域


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

這時,因爲存在跨域,瀏覽器不會進行重定向;可是可否經過上面的代碼來用JavaScript進行重定向呢?

抱歉,一樣不能夠;這時經過ajaxComplete方法獲取到的xhr的status值,發現其值爲0,Location的header爲null;因此這種辦法行不通。更可取的方法能夠是這樣:

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

3、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的狀況

參考文獻

相關文章
相關標籤/搜索