findxc / blog

88 stars 5 forks source link

如果运维没有给 html 文件设置缓存头 #60

Open findxc opened 3 years ago

findxc commented 3 years ago

没有设置缓存头的话,那么是否会缓存和缓存有效期就依赖于浏览器的默认行为了。

想一下这个场景,当第一次在一个新标签页访问 http://hello.com 时,会去请求一个 html 文件。然后这时候我修改了 html 文件内容,然后新开一个标签页再去访问 http://hello.com ,我能请求到新的 html 吗?

没有设置缓存头时浏览器默认行为

Heuristic freshness checking 这里有介绍。

如果浏览器在请求某个资源时,服务端没有给该资源设置缓存头,比如 Cache-Control 或者 Expires ,那么浏览器会去看响应头是否有 Last-Modified 。如果有的话,那么资源的缓存有效期是 (Date - Last-Modified) * 10% 。当在这个有效期内去再次请求该资源,会直接使用浏览器缓存,不管该资源是否已经发生了变更。

比如某资源最后修改时间是10月1日,然后我在10月11日请求了该资源,那么在 1 天内,我请求该资源都会直接走浏览器缓存。(这个时间只是一个大概,浏览器具体实现可能有差异)

浏览器什么时候会在请求头自动加上 Cache-Control: max-age=0

如果你有在本地测试过 HTTP 缓存相关的各种设置(HTTP 缓存 & 用 NGINX 来验证缓存效果 · Issue #46 · findxc/blog · GitHub),你可能会发现,当你请求的资源是一个 html 文件时,浏览器会自动加上 Cache-Control: max-age=0 这个请求头,表示缓存的有效期是 0s ,下次请求该资源时,需要先找服务端验证一下缓存是否还有效,如果有效就可以直接使用缓存。

所以就算你没设置缓存头,当 html 文件更新后,浏览器也能拿到更新后的文件。

但是,只有在当前标签页手动刷新当前页面时,浏览器才会加上 Cache-Control: no-cache 。如果我是在新标签页去访问同样的链接,是不会加上的,详见 iis - Is Chrome ignoring Cache-Control: max-age? - Stack Overflow

所以这就会产生一种场景,10月1日产品上线版本 v1 ,10月11日上午用户访问了 http://hello.com 有了 v1 的缓存,10月11日下午上线版本 v2 ,用户访问 http://hello.com 看到的却还是 v1 。

并且你后续让运维再加上缓存设置用户也无法访问新版本,需要等用户那的缓存先失效才行。要不你让用户刷新一下页面,要不让用户手动清理一下浏览器缓存,都很让人觉得这个产品很不专业是不是,手动狗头。

来个总结

出现上面说的场景的本质原因是,访问某个 url 时,这个 url 对应的资源是可能变化的,那就要在上线时设好缓存头为 Cache-Control: max-age=0 ,这样资源如果有更新,再次访问时能够拿到更新后的资源。

maqi1520 commented 2 years ago

hi 文章可以转账到公众号 JS酷 吗?会注明作者和原文链接

galaxy-s10 commented 1 year ago

说白了就是设置强缓存,不缓存html文件是吧

findxc commented 1 year ago

@galaxy-s10 Cache-Control: max-age=0 是协商缓存,协商缓存浏览器也会缓存,但是它会在需要这个资源时,发请求验证一下这个资源是否有更新。强制缓存不会验证。

galaxy-s10 commented 1 year ago

@galaxy-s10 Cache-Control: max-age=0 是协商缓存,协商缓存浏览器也会缓存,但是它会在需要这个资源时,发请求验证一下这个资源是否有更新。强制缓存不会验证。

yes,可以再总结一下就是:在后端or运维没有配置请求头的情况下,某些浏览器会有自己的一套缓存规则((Date - Last-Modified) * 10%),后端or运维配置了max-age=0约等于走了协商缓存(max-age本身其实是做强缓存的,但是max-age=0约等于走了协商缓存)。