簡體   English   中英

jQuery ajax ifModified 在調用緩存響應時不兌現應該是 304

[英]jQuery ajax ifModified not honored on call for cached response when should be 304

我正在使用 jQuery ajax 從 ASP.Net MVC 應用程序中檢索 json 並且在ifModified = true進行 ajax 調用時沒有看到預期的結果。

我使用的是 jQuery 1.9.1 和 Chrome 版本 26.0.1410.64 m

當使用新的瀏覽器實例並對已經緩存的內容發出初始請求時,即使在 ajax 配置中設置了 ifModified=true,也不會調用服務器來檢查緩存狀態。 在來自同一瀏覽器實例的后續請求中,(預期)會調用服務器,服務器以 304 響應。

在初始請求中,瀏覽器網絡跟蹤顯示內容是從緩存傳遞的,狀態為 200,即使從未檢查過修改日期。 Fiddler 顯示未發出任何請求,並且未命中 ASP.Net MVC 控制器中的斷點。

這是一個錯誤,還是有辦法讓它正常工作? 如果它是一個錯誤,它是一個 jQuery 錯誤還是一個 Chrome 錯誤?

這是一個簡化的 ajax 調用:

var req = $.ajax({
    type: "GET",
    dataType: "json",
    url: "/JsonTest/GetJson",
    ifModified: true,
    success: function (data, status, jqXHR) {
        if (data === undefined && status == "notmodified") {
            $.ajax({
                type: this.type,
                dataType: this.dataType,
                url: this.url,
                ifModified: false,
                success: this.success,
                error: this.error,
                complete: this.complete
            });
        } else {
            alert($.toJSON(data));
        }
    },
    error: function (jqXHR, status, error) {
        alert(error);
    },
    complete: function (jqXHR, status) {
    }
});

這是一個簡化的 ASP.Net MVC 控制器方法:

[AllowAnonymous]
public ActionResult GetJson()
{
    // dummy data version.
    var currentVersion = new DateTime(2013, 04, 30, 12, 0, 0);

    // get client cached version from request
    DateTime cachedVersion;
    if (DateTime.TryParseExact(HttpContext.Request.Headers["If-Modified-Since"], "r", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out cachedVersion))
    {
        cachedVersion = cachedVersion.ToLocalTime();
    }
    else
    {
        cachedVersion = DateTime.MinValue;
    }

    // return 304 if not changed
    if (currentVersion.Subtract(cachedVersion).Duration() < TimeSpan.FromSeconds(1))
    {
        HttpContext.Response.StatusCode = 304;
        HttpContext.Response.StatusDescription = "Not Modified";
        return new EmptyResult();
    }

    // still here? return current object and set current version response header
    var rv = new { name = "Hello", value = "World" };
    HttpContext.Response.Cache.SetCacheability(HttpCacheability.Private);
    HttpContext.Response.Cache.SetLastModified(currentVersion);
    return Json(rv, JsonRequestBehavior.AllowGet);
}

重現步驟:1)啟動新的瀏覽器實例 2)發起ajax請求 3)關閉響應提醒窗口 4)發起ajax請求 5)關閉瀏覽器重復

第一次通過,空緩存:第 2 步向服務器發出請求。 服務器響應 200。第 4 步向服務器發出請求,服務器響應 304。

第二次通過 - 緩存中的響應:第 2 步不向服務器發出請求。 響應從狀態為 200 的緩存中獲取。 步驟 4 向服務器發出請求,服務器響應 304。

我希望第二次通過第 2 步向服務器發出請求並收到 304。

每次使用緩存源時都無法檢查緩存源的狀態是一個大問題,因為緩存數據可能已經過時,但用戶在同一瀏覽器實例中發出后續請求之前不會知道它。

這里發生了兩件事:

  1. Chrome 緩存過於激進。

  2. ifModified=true可能不會你認為的那樣做。

Chrome 應該始終向服務器發送請求以驗證緩存資源的有效性,但有時它似乎根本沒有。 這種行為經常讓 Web 開發人員感到沮喪,他們在開發過程中迅速改變了他們的資源。

當發出請求的腳本顯式設置緩存標頭時,JavaScript 只能觀察304響應。 JavaScript 無法利用瀏覽器已知的緩存日期信息; 任何緩存日期信息都必須由腳本本身發現或選擇(可能通過讀取先前響應的最后修改的標頭)。 給瀏覽器的實際304響應將作為200響應報告給 JavaScript,除非 JavaScript 設置If-Modified-Since標頭(或其他緩存標頭)。

使用 jQuery 對資源的第一次獲取永遠不會返回304 這是因為 jQuery 不會保存值以在頁面加載之間與If-Modified-Since標頭一起使用。 請參閱我關於如何檢查 jQuery.ajax() 請求標頭狀態是否為“304 未修改”的回答?

然而,jQuery 不會在頁面重新加載之間保留緩存信息(例如,在 cookie 中)。 因此,頁面重新加載后對資源的第一次獲取永遠不會是 304,因為 jQuery 沒有要發送的緩存信息(即,我們重置回“第一次獲取”的情況)。 jQuery 沒有理由不能持久化緩存信息,但目前它沒有。

原因是 304 請求總是返回空的 假設您的代碼在第一次返回時將響應存儲為 200,但 jQuery 不想強加要求您在頁面重新加載時保存緩存的結果。

我通過跟蹤初始請求並將 beforeSend 添加到 ajax 配置解決了行為問題:

window.resourceInitializers = {};
...
beforeSend: function (jqXHR, settings) {
    if (!window.resourceInitializers['GetJson']) {
        jqXHR.setRequestHeader("If-Modified-Since", "Sat, 01 Jan 2000 00:00:01 GMT")
        window.resourceInitializers['GetJson'] = true;
    }
},
...

不幸的副作用是資源總是在頁面重新加載時檢索,而不管其緩存狀態如何。

暫無
暫無

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

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