我們知道,只有請求成功ajax才會進行回調處理,具體狀態碼為 status >= 200 && status < 300 || status 304; 這一點通過查看JQuery的源碼就可以證實。 舉個例子來說明,用ajax來實現重定向,ajax非同步請求A,A內部重定向到B。 思考: Q1:ajax ...
我們知道,只有請求成功ajax才會進行回調處理,具體狀態碼為 status >= 200 && status < 300 || status === 304; 這一點通過查看JQuery的源碼就可以證實。
// Cache response headers responseHeadersString = headers || ""; // Set readyState jqXHR.readyState = status > 0 ? 4 : 0; // Determine if successful isSuccess = status >= 200 && status < 300 || status === 304;//確定請求是否成功. // Get response data if ( responses ) { response = ajaxHandleResponses( s, jqXHR, responses ); } // Convert no matter what (that way responseXXX fields are always set) response = ajaxConvert( s, response, jqXHR, isSuccess ); // If successful, handle type chaining if ( isSuccess ) { // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. if ( s.ifModified ) { modified = jqXHR.getResponseHeader("Last-Modified"); if ( modified ) { jQuery.lastModified[ cacheURL ] = modified; } modified = jqXHR.getResponseHeader("etag"); if ( modified ) { jQuery.etag[ cacheURL ] = modified; } } // if no content if ( status === 204 || s.type === "HEAD" ) { statusText = "nocontent"; // if not modified } else if ( status === 304 ) { statusText = "notmodified"; // If we have data, let's convert it } else { statusText = response.state; success = response.data; error = response.error; isSuccess = !error; } } else { // We extract error from statusText // then normalize statusText and status for non-aborts error = statusText; if ( status || !statusText ) { statusText = "error"; if ( status < 0 ) { status = 0; } } }
舉個例子來說明,用ajax來實現重定向,ajax非同步請求A,A內部重定向到B。
思考:
Q1:ajax回調方法是否會被執行?
Q2:ajax能否重定向?
var mobile = $("input[name='mobile']").val(); $.post("/recharge/pay", {mobile:mobile}, function(backData) { alert("執行回調"); alert(backData); }).complete(function(xhr) { alert("請求狀態碼:"+xhr.status); });
@RequestMapping(value = "/recharge/m{mobile}",method = RequestMethod.GET) public String rechargeB(@PathVariable String mobile, ModelMap model){ model.put("mobile",mobile); return "user/recharge"; } @RequestMapping(value = "/recharge/pay",method = RequestMethod.POST) public String rechargeA(String mobile){ String rechargeUrl = "/recharge/m19012345678"; return "redirect:"+rechargeUrl; }
測試之後發現,回調方法能正常執行,返回的狀態碼也是200,這裡具體是怎麼執行的呢?首先,ajax post 請求到/recharge/pay之後,A方法內部進行重定向,這個時候返回的狀態碼應該是302;其次,A重定向到B之後,執行完成返回的狀態碼應該是200;回調方法是在B執行完才執行的。通過谷歌瀏覽器的Network可證實。
這個問題可參考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重定向——從Response Headers中讀取Location信息,然後向Location中的Url發出請求,在收到這個請求的響應後才會進行ajax回調處理。大致流程如下:
ajax -> browser -> server -> 302 -> browser(redirect) -> server -> browser -> ajax callback
而在我們的測試程式中,由於302返回的重定向URL在伺服器上有相應的處理程式,所以在ajax回調函數中得到的狀態碼是200。
所以,如果你想在ajax請求中根據302響應通過location.href進行重定向是不可行的。
在測試的時候註意一下,如果你指定了ajax的第4個參數dataType(預期伺服器返回的數據類型),可能不會觸發回調方法,因為這裡會先執行重定向,也就是說,重定向後的內容會作為ajax的介面內容來響應,調試時你也能看見backData的內容不是json字元串,而是重定向到B頁面的html字元串。其實這個測試示例的流程本身就存在著問題,ajax請求的地址應該只返回數據,而不是重定向。
另外需要註意的一點是,get、post就是在ajax的基礎上進行封裝的,只封裝了success,並沒有封裝error方法,所以,只要請求返回的狀態碼不是200-300,就不會走回調方法,見源碼。
jQuery.each( [ "get", "post" ], function( i, method ) { jQuery[ method ] = function( url, data, callback, type ) { // shift arguments if data argument was omitted if ( jQuery.isFunction( data ) ) { type = type || callback; callback = data; data = undefined; } return jQuery.ajax({ url: url, type: method, dataType: type, data: data, success: callback //只封裝了success方法,沒有error。 }); }; });
總結:
1、ajax主要用於非同步請求數據,而不是重定向,它只負責獲取數據或處理結果;
2、只有狀態碼 status>=200 && status<300 || status==304 ,才被視為success,才會走success的回調方法;
3、post、get 只封裝了ajax的success方法。
附參考文獻