jquery.ajax中的ifModified參數的誤解

原來覺得ifModified是爲了在AJAX請求是發送 If-Modified-Since頭,讓服務端返回304。html

測試代碼以下:jquery

 

$(function () {
    test();
    window.setTimeout(test, 5000);
});

function test() {
    $.ajax({
        type: "GET",
        url: url,
        ifModified: true,
        success: function (d, textStatus, xhr) {
           console.log(xhr.status);
	    console.log(d == undefined);
        }
    });
}

chrome:ajax

network 爲 304,304chrome

console爲  200 false, 304 trueapi

ie10瀏覽器

network爲 304, 304緩存

console爲 200 false, 304 true服務器

firefox:app

network爲 304, 200(from cache)ide

console爲 200 false, 200 false

 

上述測試是創建在已經訪問過的基礎上進行的,所以第一個請求都爲304。

測試結果有幾個疑問

一、爲何network監控的響應碼與jqXHR.status有不一致的狀況

二、chrome與ie10爲何第一次請求能夠獲取到內容,但一樣的304返回,第二次卻內容爲undefined

三、firefox的第二次請求爲何直接從cache取數據

 

據文檔 XHR API

For 304 Not Modified responses that are a result of a user agent generated conditional request the user agent must act as if the server gave a 200 OK response with the appropriate content. The user agent must allow setRequestHeader() to override automatic cache validation by setting request headers (e.g., If-None-Match, If-Modified-Since), in which case 304 Not Modified responses must be passed through.

就是說通常狀況下,若是服務器返回304後,瀏覽器會進行轉換。此時jqXHR.status應該是200,而且瀏覽器會自動將緩存的內容發送給jqXHR(304,服務器是不會發送內容信息的);

但能夠經過jqXHR.setRequestHeader(If-Modified-Since)來重載該行爲,若是服務端會返回304,則把該結果直接傳遞給 jqXHR。

據此咱們回答了第一個疑問。

 

那麼第二個問題是怎麼回事?

查看了network中的請求,二次請求都有帶 If-Modified-Since 的頭,沒什麼發現

在jq的源碼發現瞭如下代碼

// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {

	if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
		jQuery.lastModified[ ifModifiedKey ] = lastModified;
	}
	if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
		jQuery.etag[ ifModifiedKey ] = etag;
	}
}

這是從響應獲取Last-Modified頭的過程

// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
	ifModifiedKey = ifModifiedKey || s.url;
	if ( jQuery.lastModified[ ifModifiedKey ] ) {
		jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
	}
	if ( jQuery.etag[ ifModifiedKey ] ) {
		jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
	}
}

這是設置If-Modified-Since頭的過程

回到主題 ifModified 參數,文檔以下

Allow the request to be successful only if the response has changed since the last request. This is done by checking the Last-Modified header. Default value is false, ignoring the header. In jQuery 1.4 this technique also checks the 'etag' specified by the server to catch unmodified data.

文檔說得不是很清楚,看代碼的實現。

jq根據jQuery.lastModified字典中是否包含數據來決定是否設置If-Modified-Since。那第一次請求jQuery.lastModified是沒有數據的(JS是沒法獲取瀏覽器緩存的信息),所以第一次請求jqXHR是沒有設置If-Modified-Since,那也就解釋了第一次請求jqXHR.status爲200。由於有了第一次請求,jq獲取獲取到第一次請求響應中的Last-ModifiedjQuery.lastModified有了數據,第二次請求jqXHR是會加上If-Modified-Since頭的,所以jqXHR.status收到了瀏覽器直接傳遞過來的請求響應及內容。

搞定了第二個疑問。

 

第三個問題看了一些文檔尚未明確的結論,估計是firefox在xhr在處理cache上有些不一樣,服務器響應頭有包含

Cache-Control:public, max-age=18000

 

總結下:

jquery ifModified參數主要是爲了在經過JS檢測資源是否發生變化(304),而且在頁面的第一個AJAX請求jqXHR.status永遠不會返回304。

參考文檔

一、http://www.w3.org/TR/2009/WD-XMLHttpRequest-20091119/

二、http://stackoverflow.com/questions/5173656/how-to-check-if-jquery-ajax-request-header-status-is-304-not-modified

三、https://bugzilla.mozilla.org/show_bug.cgi?id=428916

相關文章
相關標籤/搜索