2011-03-02 49 views
40

如何檢查請求頭是否爲jQuery.ajax()狀態爲「304未修改」?如何檢查jQuery.ajax()請求標題狀態是否爲「304未修改」?

jqXHR.status通常會返回200,即使請求標頭爲「304未修改」。

ifModified:truedoes not help很多因爲它打破了XHR數據請求。

+1

簡短的回答是沒有。但是,這是[確定什麼jQuery .ajax()解決重定向到一個字符串]的可能重複(http://stackoverflow.com/questions/6767618/determining-what-jquery-ajax-resolves-a-string- )雖然不是完全相同的問題,但概念是相同的 - XHR規範不需要任何3xx響應的通知。 – JAAulde 2012-09-19 19:32:16

+0

值得注意的是,您不需要手動執行ETag檢查,從您的JavaScript中,瀏覽器將爲您處理它。所以,除非你有特殊的理由,否則通常你不需要檢查304響應 – Anentropic 2014-10-13 12:13:05

回答

59

不用手動處理緩存標題,這是不可能的。通常情況下,304個響應不通過XHR API提供:

對於304未修改是用戶代理的結果而生成條件請求彷彿服務器給出了與一個200 OK響應的用戶代理必須採取行動的響應適當的內容

jQuery通常不知道有304響應,因爲瀏覽器告訴禮貌的謊言JavaScript的有關網絡上實際發生的事情。

不過也有好消息(種):你可以得到阿賈克斯產生304響應,但只能通過手動設置HTTP cache headersIf-Modified-SinceIf-None-Match在請求:

用戶代理必須允許setRequestHeader()通過設置請求標頭(例如,If-None-Match,If-Modified-Since)覆蓋自動緩存驗證,在這種情況下必須傳遞304個未修改的響應。

所以,你可以使用如下代碼:

var xhr = new XMLHttpRequest(); 
xhr.open("GET", "foo.html"); 
xhr.setRequestHeader("If-Modified-Since", "Fri, 15 Feb 2013 13:43:19 GMT"); 
xhr.send(); 

一個主要困難是你怎麼知道送什麼最後修改日期或ETag瀏覽器具有用於發送請求的緩存信息,但不會與JavaScript共享該信息。幸運的是,jQuery跟蹤來自Ajax響應的Last-ModifiedETag標題,因此您可以使用ifModified:true讓jQuery在下次向該資源發送請求時設置這些標題值。

有兩點需要注意一下:

  • 304的反應不攜帶數據。這是設計。假設是,如果您選擇使用緩存,則您的應該有一個已經在緩存中的數據副本!如果沒有從服務器獲取數據是一個問題(即,因爲您還沒有該數據),您爲什麼使用緩存?當您手頭有舊數據並且只需要新數據時應該使用緩存;因此,使用304取回數據不應該成爲問題。

  • jQuery必須具有上次請求存儲的最後修改日期或ETag(與If-None-Match一起使用)。過程是這樣的:

    • 首先獲取:jQuery有沒有緩存的信息,所以它不會發送If-Modified-SinceIf-None-Match。當響應返回時,服務器可能會發布最後修改的數據或ETag,jQuery存儲該數據以備將來使用。

    • 隨後取:jQuery有從過去的高速緩存信息獲取和轉發數據到服務器。如果資源沒有改變,Ajax請求會得到一個304響應。如果資源發生了變化,Ajax請求得到一個200響應,jQuery的新的緩存信息一起以用於其下獲取。

    • jQuery 不是然而,在頁面重新加載之間存儲緩存信息(例如,在cookie中)。因此,第一次提取的資源的頁面重新加載後會永遠是304,因爲jQuery沒有緩存信息發送(即,我們重新回到了「先取」的情況下)。沒有理由的jQuery 不能堅持緩存信息,但目前它沒有。

這裏的底線是,你可以使用緩存頭以獲取JavaScript 304響應,但你不能對特定資源訪問瀏覽器自身的ETag或最後修改日期。所以,瀏覽器本身可能知道關於資源的緩存信息,但是你的JavaScript代碼卻不知道。在這種情況下,瀏覽器將使用緩存標頭可能得到真正的304響應,但轉發200響應你的JavaScript代碼,因爲JavaScript和沒有發送任何緩存信息。

這是不可能做出的JavaScript 304請求與實際網絡304的響應完全一致,因爲您的瀏覽器,並通過你的JavaScript代碼中已知的高速緩存信息稱爲緩存的信息可以在不可預知的方式有所不同。但是,大多數時候正確地獲得304請求對於大多數實際的開發需求來說已經足夠好了。

這裏是寫在Node.js的一個簡短的服務器實例(但它應該是移植到其他漢語語言很簡單):

require("http").createServer(function (req, res) { 
    console.log(req.headers["if-modified-since"]); 

    // always send Last-Modifed header 
    var lastModDate = "Fri, 13 Feb 2013 13:43:19 GMT"; 
    res.setHeader("Last-Modified", lastModDate); 

    // if the request has a If-Modified-Since header, 
    // and it's newer than the last modification, 
    // then send a 304 response; otherwise send 200 
    if(req.headers["if-modified-since"] && 
    Date.parse(lastModDate) <= Date.parse(req.headers["if-modified-since"])) { 
    console.log("304 -- browser has it cached"); 
    res.writeHead(304, {'Content-Type': 'text/plain'}); 
    res.end(); 
    } else { 
    console.log("200 -- browser needs it fresh"); 
    res.writeHead(200, {'Content-Type': 'text/plain'}); 
    res.end('some content'); 
    } 

}).listen(8080); 

當運行該服務器,您可以加載頁面在瀏覽器,在您的瀏覽器控制檯執行兩個不同的測試:

var xhr = new XMLHttpRequest(); 
xhr.open("GET", "/"); 
xhr.send(); 
xhr.onload = function() { console.log(xhr.status); } 

這個腳本總會看到一個200響應,即使瀏覽器小號提供If-Modified-Since請求標頭並獲得304(在瀏覽器看到服務器的Last-Modifed響應標頭後,將在第一個請求後發生所有請求)。

相比之下,該腳本將總是看到304響應:

var xhr = new XMLHttpRequest(); 
xhr.open("GET", "/"); 
xhr.setRequestHeader("If-Modified-Since", "Fri, 15 Feb 2013 13:43:19 GMT"); 
xhr.send(); 
xhr.onload = function() { console.log(xhr.status); } 

腳本(服務器的最後修改日期後兩天)提供它自己的If-Modified-Since請求頭;它不依賴於瀏覽器爲If-Modified-Since提供的任何內容,因此允許(根據XHR規範)查看304個響應。

最後,該腳本將總能看到200

var xhr = new XMLHttpRequest(); 
xhr.open("GET", "/"); 
xhr.setRequestHeader("If-Modified-Since", "Fri, 12 Feb 2013 13:43:19 GMT"); 
xhr.send(); 
xhr.onload = function() { console.log(xhr.status); } 

這是因爲該腳本使用If-Modified-Since之前服務器的最後修改的日期,因此服務器總是發送200。服務器不會發送304,因爲它假定客戶端沒有最新版本的緩存副本(即客戶端宣佈自2月12日以來發生更改,但在2月13日發生了變更,客戶端顯然還沒有見過)。

+0

正確的答案。 – JAAulde 2012-09-19 19:43:33

+0

「用戶代理必須允許setRequestHeader()通過設置請求標頭(例如,If-None-Match,If-Modified-Since)來覆蓋自動緩存驗證,在這種情況下必須通過304個未修改響應。[RFC2616] 「 – 2013-02-14 21:06:55

+0

@ChristopherJamesCalo我承認我之前的回答是可悲的不完整 - 我已經擴展了我的回答,談論如何在JavaScript中使用緩存頭。 – apsillers 2013-02-15 14:35:56

-5

也許試試這個?

$.ajax({ 
    url: 'your-url', 
    dataType: 'script', 
    complete: function(xhr) { 
     if (xhr.status == 304) return; 
     // or better: if (xhr.status != 200) return; 
     // your code goes here 
    } 
}); 
+3

這是行不通的。 – Binyamin 2011-03-02 21:48:42

+0

XHR'readsystatechange'沒有被3xx響應觸發,所以當'status'是304時'complete'不會被輸入。 – JAAulde 2012-09-19 19:41:53

-5

打開您的瀏覽器檢查器,它會告訴您有關ajax請求的信息,包括狀態。

for chrome,右鍵單擊並選擇檢查元素,然後轉到網絡選項卡。

對於Firefox,只需使用螢火蟲,並按照相同的步驟。

+2

這隻能幫助OP瞭解到觀察的人。我相信他會希望他的計劃能夠「知道」並根據這些信息做出決定。 – JAAulde 2012-09-19 19:44:35

0

此外,如果響應來自緩存頭將被緩存。我把這當成了一次機會。 我的服務器發送一個唯一的md5頭。這與?query = time()不一樣。現在在JS端驗證當前最新的md5頭。如果您收到的響應來自緩存,則會收到與之前相同的MD5標頭。我忘了所有關於JQuery,但看到它可以設置和讀取標題。

<?php 
$oldMD5=filter_input(INPUT_SERVER,'HTTP_CONTENT_MD5',int); 
if(!empty($oldMD5)){ 
    header('Content-MD5: '.(1+(int)$oldMD5)); 
} 
-------------------------------------------------------------- 
<script> 
var oldMD5=0; 
//your Ajax implementation 
Ajax.setRequestHeader('Content-MD5',''+oldMD5); 
var newMD5=parseInt(Ajax.getResponseHeader('Content-MD5'),10); 
if(newMD5 && oldMD5<newMD5,10){ 
    oldMD5=newMD5; 
    //not cached 
}else{ 
    //cached 
} 

這是一個有點濫用,因爲MD5應該是驗證「解碼的數據是最初發送相同的數據」哈希值。