4

我有一个网站,其中包含不变的静态资产(js、图像等)。这些资产中的每一个都具有带有以下属性的缓存控制标头集:

cache-control: public, max-age=31536000, immutable

但是,当我重新加载页面时,我仍然看到来自服务器的 200 响应而不是 304 响应。浏览器指示资产正在从内存或磁盘缓存中提供服务,但它仍在发出请求并下载内容。这以前可以工作,我倾向于这是一个浏览器错误,但我不完全确定。

4

5 回答 5

3

评论中讨论的内容以及凯文提到的内容,您似乎误解了条件获取请求。

有很多问题你可能想得到答案:

1. 为什么浏览器的状态是 HTTP 200 而不是 304?

当浏览器加载任何文档时,对静态资源的请求将通过缓存处理程序,如果资源存在于本地缓存中,则请求将通过缓存处理程序发送到服务器,响应将具有 HTTP 200 状态,而不是向服务器发送请求。

例如,对于这个 stackoverflow 页面,当我刷新页面时,我还会在jQuery的网络选项卡中看到类似的内容。

在此处输入图像描述

但是没有任何请求来获取资源。看fiddler,有建立HTTPS连接的请求,但是没有获取jQuery。

在此处输入图像描述

2. 浏览器什么时候发送条件请求?

当缓存过期时,用户代理将发送条件获取请求来验证内容是否被修改,如果资源没有被修改,服务器将发送 HTTP 304 响应并随之共享内容的新过期日期。

在此处输入图像描述

对于我们的 jQuery 示例,您可以从邮递员发送以下请求:

GET https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
Header:
Cache-Control: public
If-Modified-Since: Tue, 03 Mar 2020 19:15:00 GMT

您将收到以下回复并更新到期日期:

HTTP 304
Date: Fri, 16 Oct 2020 08:58:03 GMT
Expires: Sat, 16 Oct 2021 08:58:03 GMT
Age: 32066

不赘述,缓存可以概括为:

1. User agent sends request to server
2. Server responds resource along with "Last-Modified" date
3. Next time same resource is requested, browser will use "Last-Modified" date (aka validator) to check if resource is stale or not
    3.1 If resource is not stale, it will be served from cache
    3.2 If resource is stale, browser will use "Last-Modified" date in header and **send conditional get** to server
        3.2.1 server can resource and send HTTP 200 is resource is updated
        3.2.2 In case resource is not modified, server will send HTTP 304 along with updated `Expiry` date

3. 为什么它以前工作?

老实说,我不知道为什么它以前有效。可能有多种原因:

  1. 可能是您的浏览器缓存旧并且缓存资源的标头具有旧值,Last-Modified因为从您的用户代理发送了条件获取请求并且服务器返回了缓存资源(响应标头)的更新Last-Modified日期。Expires
  2. 可能是浏览器禁用了缓存(隐身模式或显式使用无缓存)
  3. 可能是服务器早先不支持缓存并且没有发送Last-Modified响应等等。

参考:

  1. https://web.dev/http-cache/
  2. https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
  3. https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
于 2020-10-16T18:43:25.793 回答
0

尝试删除标签immutable并使用:

Cache-Control: public, max-age=31536000;

您可以在Mozilla 的Cache-Control文档中了解更多信息。

于 2020-10-22T18:56:54.370 回答
0

您所描述的只是 Chrome 开发工具如何显示缓存提供的响应。还有其他 StackOverflow 问题(比如这个)可以证实这一点。

状态代码显示为200因为它就是这样。响应被缓存,响应的一部分是状态码。缓存响应没有特殊的状态代码。

你误解了304它的用途。用于回复有条件的请求。它表示通过网络接收到的具有该状态代码的实际响应,而不是缓存响应。

要确认响应确实是从缓存中提供的,并且没有新请求发送到服务器,您可以查看服务器日志。

于 2020-10-16T11:59:45.153 回答
0

当检索到 URL 时,Web 服务器将返回资源的当前表示形式及其对应的 ETag 值,该值放置在 HTTP 响应标头“ETag”字段中。

然后,客户端可以决定缓存该表示及其 ETag。

稍后,如果客户端要再次检索相同的 URL 资源,它会首先确定该 URL 的本地缓存版本是否已过期(通过 Cache-Control 和 Expire 标头)。如果 URL 没有过期,它将检索本地缓存的资源。如果它确定 URL 已过期(过时),则客户端将联系服务器并将其先前保存的 ETag 副本与请求一起发送到“If-None-Match”字段中。(来源:https ://en.wikipedia.org/wiki/HTTP_ETag )

但是,即使expire将来设置了资产的时间,浏览器仍然可以根据Vary标头使用 ETag 访问服务器以进行条件 GET。

“变化”标题的详细信息:https ://www.fastly.com/blog/best-practices-using-vary-header/ :

所以现在缓存中有一个对象,上面有一个小标志,上面写着“仅用于请求中没有 Accept-Encoding 的请求”。

于 2020-10-22T12:28:49.750 回答
0

这可能无法回答问题,但可能对其他人有所帮助。

我遇到了同样的问题,我的许多资产都没有被 Chrome 正确缓存。在所有其他浏览器上都可以正常工作,但在 Chrome 上却不行。我意识到其中一个区别是我在 Firefox 上得到的 304 响应,但在 Chrome 上却没有。此外,内存缓存和磁盘缓存返回了一些文件,但有时它不会。

我尝试修改 Cache-Control 标头和 ETag,但仍然没有解决方案。

然后我意识到它在具有有效证书的 QA 和生产环境中运行良好。但在开发(本地主机)上,它不是。所以我找到了这个 Chrome 配置:

chrome://flags/#allow-insecure-localhost

启用它只是通过问题修复。希望它可以帮助其他人。

于 2021-03-04T01:00:09.590 回答