jQuery ajax ifModified在调用缓存响应时不被尊重,而应该是304



我使用jQuery ajax从ASP检索json。. Net MVC应用程序,我没有看到预期的结果时,使ajax调用其中的ifModified = true

我使用jQuery 1.9.1和Chrome版本26.0.1410.64 m

当使用一个新的浏览器实例并对已经缓存的内容进行初始请求时,即使在ajax配置中设置了ifModified=true,也不会调用服务器来检查缓存状态。对于来自同一浏览器实例的后续请求,将(预期地)对服务器进行调用,服务器将使用304响应。

在初始请求中,浏览器网络跟踪显示内容是从状态为200的缓存中传递的,尽管从未检查过修改的日期。Fiddler显示没有发出请求,ASP中出现了一个断点。. Net MVC控制器未命中。

这是一个bug,还是有办法让它正常工作?如果它是一个bug,它是一个jQuery bug还是一个Chrome bug?

下面是一个简化的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。step4向服务器发出请求,服务器响应304.

第二次通过缓存响应:step2不向服务器发出请求。响应从状态为200的缓存中获取。step4向服务器发出请求,服务器响应304.

我希望第二次通过的步骤#2向服务器发出请求并收到304。

每次使用时检查缓存源状态的失败是一个大问题,因为缓存的数据可能是过时的,但用户不会知道,直到他们在同一个浏览器实例中发出后续请求。

这里发生了两件事:

  1. Chrome缓存过度

  2. ifModified=true可能不像你想象的那样

Chrome应该总是向服务器发送请求来验证缓存资源的有效性,但有时它似乎根本没有。这种行为经常使在开发过程中快速更改资源的Web开发人员感到沮丧。

JavaScript只能在发出请求的脚本显式设置缓存头时观察304响应。JavaScript不能利用浏览器已知的缓存日期信息;任何缓存日期信息都必须由脚本自己发现或选择(可能是通过读取上一次修改的前一个响应的标头)。实际的304响应给浏览器将报告给JavaScript作为200响应,除非JavaScript设置If-Modified-Since头(或其他缓存头)。

第一次使用jQuery获取资源将永远不会返回304。这是因为jQuery不会在页面加载之间保存If-Modified-Since头使用的值。看到我的回答如何检查如果jQuery.ajax()请求头状态是"304未修改"?:

然而,在页面重新加载之间,jQuery不保留缓存信息(例如,在cookie中)。因此,在页面重新加载后第一次获取资源永远不会是304,因为jQuery没有缓存信息要发送(即,我们重置回"第一次获取"的情况)。jQuery 没有理由不能持久化缓存信息,但目前它还不能。
304请求总是返回空的原因。假设您的代码在响应第一次作为200返回时存储响应,但是jQuery不想强制要求您在页面重新加载时保存缓存结果。

我通过跟踪初始请求并将beforeend添加到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;
    }
},
...
的副作用是,资源总是在页面加载时检索,而不管其缓存状态如何。

最新更新