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安全
隨着公司業務的發展新的狀況出現了,公司要將登陸認證統一到某臺公共的服務器上,這時,失效的用戶在ajax獲取數據時狀態失效而被重定向到登陸頁面;因爲當前系統與登陸頁面不一樣域,而XHR不容許跨域訪問數據,因此ajax的302也存在跨域問題。(不像頁面之間重定向不存在這個問題,你能夠訪問當前系統的某個頁面,服務能夠重定向到www.baidu.com而不會有跨域問題)。
這時,因爲存在跨域,瀏覽器不會進行重定向;可是可否經過上面的代碼來用JavaScript進行重定向呢?
抱歉,一樣不能夠;這時經過ajaxComplete方法獲取到的xhr的status值,發現其值爲0,Location的header爲null;因此這種辦法行不通。更可取的方法能夠是這樣:
首先不要在服務器端進行重定向;而後經過接口的形式或者在response添加一個自定義header來區分重定向信息;最後由JavaScript來進行重定向
翻看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的狀況