问题描述
我有一个静态资产不变的网站(js,图像等)。这些资产中的每一个都设置了具有以下属性的缓存控制标头:
cache-control: public,max-age=31536000,immutable
但是,当我重新加载页面时,我仍然从服务器看到200条响应,而不是304条响应。浏览器指示正在从内存或磁盘缓存中提供资产,但仍在发出请求并下载内容。这以前曾经有用,我倾向于将其作为浏览器错误,但我不确定。
解决方法
评论中讨论的内容以及Kevin提到的内容,您似乎对conditional get的请求有误解。
您可能想回答以下问题:
1。为什么浏览器获取HTTP 200状态而不是304状态?
当浏览器加载任何文档时,对静态资源的请求将通过缓存处理程序,并且如果本地缓存中存在资源,则请求将由缓存处理程序作为服务器,并且响应将具有HTTP 200状态,而不是向服务器发送请求。
例如,对于此stackoverflow页面,当我刷新页面时,例如,在 jQuery 的网络标签中也会看到类似的内容。
,但是没有任何获取资源的请求。看着提琴手,有一个请求建立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。为什么以前可以使用?
说实话,我不确定它为什么能工作。可能有多种原因:
- 您的浏览器缓存可能很旧,并且缓存资源的
Last-Modified
标头具有旧值,原因是从您的用户代理发送了条件获取请求,并且服务器在缓存资源上返回了更新的Last-Modified
日期(Expires
响应标头)。 - 可能是浏览器禁用了缓存(隐身模式或显式使用无缓存)
- 服务器可能不支持更早的缓存并且没有发送
Last-Modified
作为响应 等等。
参考:
- https://web.dev/http-cache/
- https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
- https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
您所描述的只是Chrome开发者工具如何显示来自缓存的响应。还有其他StackOverflow问题(例如this one)可以证实这一点。
状态代码显示为200
,因为它就是这样。响应被缓存,响应的一部分是状态码。缓存的响应没有特殊的状态代码。
您误解了304
的用途。用来回复conditional request。它代表通过网络接收到的带有该状态码的实际响应,而不是缓存的响应。
要确认响应确实是从缓存中得到的,并且没有新的请求发送到服务器,您可以查看服务器日志。
,检索到URL后,Web服务器将返回资源的当前表示形式及其相应的ETag值,该值位于HTTP响应标头“ ETag”字段中。
然后,客户端可以决定将表示形式及其ETag一起缓存。
稍后,如果客户端要再次检索相同的URL资源,它将首先确定URL的本地缓存版本是否已过期(通过Cache-Control和Expire标头)。如果URL尚未过期,它将检索本地缓存的资源。如果确定URL已过期(过时),则客户端将与服务器联系,并在“ If-None-Match”字段中发送其先前保存的ETag副本以及请求。 (来源:https://en.wikipedia.org/wiki/HTTP_ETag)
但是,即使将来设置了资产的expire
时间,浏览器仍然可以按照Vary
标头使用ETag到达服务器以进行条件GET。
“ vary”标头的详细信息:https://www.fastly.com/blog/best-practices-using-vary-header/:
,所以现在缓存中有一个对象,上面有一个小标志,上面写着“仅用于请求中没有接受编码的请求。”
尝试删除标签immutable
并使用:
Cache-Control: public,max-age=31536000;
您可以在Mozilla's Cache-Control
documentation上了解更多信息。
这可能无法回答问题,但可以对其他人有所帮助。
我遇到了同样的问题,Chrome 没有正确缓存我的许多资产。在所有其他浏览器上都可以正常工作,但在 Chrome 上不行。我意识到差异之一是我在 Firefox 上得到的 304 响应,而不是在 Chrome 上。此外,内存缓存和磁盘缓存会返回一些文件,但有时不会。
我尝试修改 Cache-Control 标头和 ETag,但仍然没有解决方案。
然后我意识到它在具有有效证书的 QA 和生产环境中运行良好。但是在开发(本地主机)上,事实并非如此。所以我找到了这个 Chrome 配置:
chrome://flags/#allow-insecure-localhost
启用它只是由问题修复。希望它可以帮助其他人。