簡體   English   中英

如何檢查jQuery.ajax()請求標頭狀態是否為“ 304未修改”?

[英]How to check if jQuery.ajax() request header Status is “304 Not Modified”?

如何檢查jQuery.ajax()請求標頭狀態是否為“ 304未修改”?

即使請求的標頭為“ 304 Not Modified”, jqXHR.status通常也返回200

ifModified:true 並沒有太大幫助,因為它中斷了XHR數據請求。

如果不手動處理高速緩存頭,則不可能。 通常, XHR API無法提供304個響應:

對於由於用戶代理生成的條件請求產生的304未修改響應, 用戶代理必須像服務器給出200 OK響應並提供適當的內容一樣起作用

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

但是有個好消息:您可以讓Ajax產生304響應,但只能通過在請求中手動設置HTTP緩存標頭 If-Modified-SinceIf-None-Match

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

因此,您可以使用如下代碼:

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 當響應返回時,服務器可以宣布jQuery存儲以供將來使用的最后修改的數據或ETag。

    • 后續提取:jQuery具有上一次提取的緩存信息,並將該數據轉發到服務器。 如果資源沒有更改,則Ajax請求將獲得304響應。 如果資源已更改,則Ajax請求將獲得200響應,以及jQuery的新緩存信息以用於下一次提取。

    • 但是,jQuery在頁面重裝之間不會保留緩存信息(例如,在cookie中)。 因此,由於jQuery沒有要發送的緩存信息,因此頁面重新加載后對資源的首次獲取將永遠不會是304(即,我們將其重置為“首次獲取”的情況)。 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日存在更改,表明客戶端顯然還沒有看到)。

另外,如果響應來自緩存,則標題也將被緩存。 我以此為契機。 我的服務器發送了一個唯一的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應該是用於驗證“解碼后的數據與最初發送的數據相同”的哈希。

我在https://github.com/laukstein/ajax-seo/blob/cbed03222d89f6f7e75dc49ce8882c30201bbb86/index.php#L266-274中有一種實現

var cache;

$.ajax({
    ...
    beforeSend: function() {
        cache = setTimeout(function() {
            console.log('The content not cached jet.');
        }, 300);
    },
    success: function(data) {
        if (cache) {
            clearTimeout(cache);
        }
    }
});

也許試試這個?

$.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
    }
});

打開瀏覽器檢查器,它將顯示有關ajax請求的信息,包括狀態。

對於Chrome,請右鍵單擊並選擇檢查元素,然后轉到“網絡”標簽。

對於firefox,只需使用firebug並遵循相同的步驟。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM