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

标签 jquery ajax google-chrome caching http-status-code-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 Controller 中的断点。

这是一个错误,还是有办法让它正常工作?如果是 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 Controller 方法:

[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 开发人员感到沮丧,因为他们在开发过程中快速更改资源。

当发出请求的脚本显式设置缓存 header 时,JavaScript 只能观察 304 响应。 JavaScript 无法利用浏览器已知的缓存日期信息;任何缓存日期信息都必须由脚本本身发现或选择(可能通过读取先前响应的最后修改的 header )。提供给浏览器的实际 304 响应将作为 200 响应报告给 JavaScript,除非 JavaScript 设置了 If-Modified-Since header (或其他缓存 header )。

第一次使用 jQuery 获取资源将永远返回304。这是因为 jQuery 不会在页面加载之间保存与 If-Modified-Since header 一起使用的值。请参阅我的回答 How to check if jQuery.ajax() request header Status is “304 Not Modified”? :

jQuery does not persist cache information (e.g., in cookies) between page reloads, however. Therefore, the first fetch of a resource after a page reload will never be a 304, because jQuery has no cache information to send (i.e., we reset back to the "first fetch" case). There is no reason why jQuery couldn't persist cache information, but at present it doesn't.

原因是 304 请求总是返回空。假设您的代码在第一次返回时存储响应为 200,但 jQuery 不希望强制要求您在页面重新加载时保存缓存结果。

关于jQuery ajax ifModified 在调用缓存响应时不被接受,而应该是 304,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16306825/

相关文章:

java - Spring Controller 必需的字符串参数不存在

javascript - Greasemonkey脚本阻止网站的其他脚本

linux - 验证 VP8 硬件编码/解码是否真的在 Linux 上工作

google-chrome - 来自谷歌 Doubleclick 响应的无效 'X-Frame-Options' header

google-chrome - 取消缩小 chrome 的堆快照

Jquery,从点击中获取url并传递给对话框中的确认按钮

jquery - 在 slider 的每张幻灯片上启动 css3 动画

php - Woocommerce 中购物车商品数量变化时自动更新购物车总计

javascript - 如果输入是复选框,则捕获正确输入的值

javascript - 通过 jQuery 附加的 HTML 不会接受点击事件