Chrome忽略ETag头,直接使用内存缓存/磁盘缓存。

27

如果我理解正确,使用ETags的流程现在如下:

  • 浏览器向服务器发送请求。服务器带着ETag返回图片。
  • 浏览器将资源和ETag一起保存。
  • 在下一次请求时,浏览器会发送包含已保存ETag的头部If-None-Match的请求。

返回响应时,Chrome开发者工具告诉我这些是我的头部

Cache-Control:max-age=7200
Connection:keep-alive
Content-Type:image/png
Date:Thu, 27 Apr 2017 13:42:57 GMT
ETag:"b36f59c868d4678033d318a182658e18371df8f5"
Expires:Thu, 27 Apr 2017 15:42:57 GMT
Server:nginx
Transfer-Encoding:chunked
X-Debug-Token:873c8f
X-Debug-Token-Link:http://localhost:8081/_profiler/873c8f

现在,当我重新加载页面时,新图片没有被获取。正如您在此处所见,它保存在Chrome的内存缓存或磁盘缓存中。

Chrome开发工具

但为什么会发生这种情况呢?我发送了一个ETag,为什么浏览器不向服务器发出另一个请求,而是使用自己的缓存?

我问这个问题的原因是,我们希望缓存我们的图像,但是一旦它们改变,它们应该立即更新。为什么Chrome会这样做呢?

更新
我刚刚注意到,Firefox上可以按照预期工作,所以这似乎是Chrome的“特性”,而不是配置问题。

更新2
设置我的新图像标头后,问题已解决,现在所有浏览器都按照预期工作。

Cache-Control:max-age=0, private
Connection:keep-alive
Content-Type:image/png
Date:Thu, 27 Apr 2017 14:44:57 GMT
ETag:"e5b18bdebe44ed4bba3acb6584d9e6a81692ee27"
Expires:Fri, 27 Oct 2017 14:44:57 GMT
Server:nginx
Transfer-Encoding:chunked
X-Debug-Token:3447a6
X-Debug-Token-Link:http://localhost:8081/_profiler/3447a6

Chrome仍然使用磁盘缓存来加载数据。这是我的nginx现在。

location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
  access_log off;
  add_header Cache-Control "max-age: 0, must-revalidate";
}

更新3
我刚刚进行了进一步的研究。只要设置了过期标签,Chrome就会使用内存或磁盘缓存。同样适用于max-age。我不明白的是,即使设置了must-revalidate,只要设置了Expiresmax-age=>0,Chrome也不重新加载资源。

4个回答

8
服务器告诉 Chrome 这个资源在未来的两小时内(7200秒)都是有效的。你第二次请求的时间很可能在这个时间段内,因此浏览器直接使用了缓存。如果你使用 max-age: 0 或者 max-age: 0, must-revalidate,服务器将发送 304 Not Modified 响应来告诉浏览器可以使用缓存实体,并根据头信息更新所有元数据。这样只需要进行请求-响应过程中传输大约300字节,而不是整个实体的几千字节。

1
这就是我们目前正在做的事情。请求发送到服务器,我们检查ETag。如果相同,则返回304响应。问题在于,它按预期工作。在Firefox中,更新图像后,新图像会立即加载。但Chrome不行。所以我不确定,您认为这是配置错误而不是Chrome错误吗? - Musterknabe
1
第五个笔记……:对不起,老兄^^。Chrome 仍然不会重新加载页面,并且仍然使用磁盘缓存。 - Musterknabe
@JonHanna 我在响应中有ETag,所以在FF和Chrome中有两种不同的行为。FF将304显示为状态码,而Chrome则显示200 OK和“来自内存/来自磁盘”。 - Maxim
3
@Musterknabe 我也遇到了同样的问题,Chrome没有发送 If-None-Match,而Firefox却有。你能找出原因吗? - manni
1
@manni 不,看起来这只是Chrome的行为方式。在我看来,他们违反了性能标准。不过在这一点上我不同意他们。 - Musterknabe
显示剩余5条评论

5

针对其他人可能遇到的情况,需要注意如果存在任何SSL错误(例如使用自签名证书),Chrome将不会缓存任何内容

提示我注意此问题的原始帖子:https://dev59.com/0mgu5IYBdhLWcg3wj3r5#55101722

Chrome bug: https://bugs.chromium.org/p/chromium/issues/detail?id=110649 (似乎他们永远不会修复它,这似乎很荒谬,因为几乎所有开发者都将在这种情况下进行开发)

尚未通过文档验证,但是似乎Edge Chromium的行为也相同。 另一方面,Firefox将高兴地遵循标准缓存规则,适用于使用“不安全”证书的站点,例如具有不完美匹配站点名称或自签名证书的站点。 我没有测试过Safari。


4

3
这是一篇旧文章,但这就是我们解决它的方式。
@Musterknabe 在你的第三次更新中做了评论:
我们也遇到了同样的问题,即使设置了must-revalidate,Chrome也没有重新加载新资源。我发现,由于资源已经存在于客户端/浏览器缓存内存中,它们正被从内存缓存中提供,并且新请求(获取静态资源)未被触发,导致响应头未更新为must-revalidate。
为了解决这个问题,我们采取了两个步骤: 1. 更改资源文件名 - 确保会触发新请求 2. 在静态文件中添加缓存控制标头(在startup.cs中)- 处理未来的静态资源文件更改。因此,今后我们不必更改资源文件名。
    public void Configure(IApplicationBuilder app)
    {
        app.UseStaticFiles(new StaticFileOptions
        {
            OnPrepareResponse = ctx =>
            {
                const int durationInSeconds = 0;
                ctx.Context.Response.Headers[HeaderNames.CacheControl] =
                    "must-revalidate,max-age=" + durationInSeconds;
            }
        });
    }

最初的回答。希望对你有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接