和浏览器较量缓存的有效/刷新时机已经很久了,看起来目前取得了比较完美的表现。

目前对一篇文章返回了以下头部字段:

1
2
3
Last-Modified: Thu, 16 May 2024 00:10:09 GMT
Etag: HEAD-1715836710-1715818209-1715817446
Cache-Control: max-age=0, must-revalidate

从上往下:

  • Last-Modified 只表示文章本身最后的修改时间。

    早期的时候我只用有这个,但是明显不够用。比如博客的主题发生了变化时,页面也应该算更新。 为了不改变这个字段本身的含义,我使用了 ETag 字段。

  • ETag 实体标签,另一种用来表示实体有没有修改过的方式,是对 Last-Modified 的补充。

    它就是个普通的字符串,内容可以自己写。我上面的格式是:${GitCommit}-${主题修改时间/系统启动时间}-${文章内容修改时间}-${评论更新时间}

    很复杂吧?其中任何一个的更新都会导致页面缓存失效。

  • Cache-Control 缓存控制。控制缓存保留的时长、刷新策略。

    max-age 表示缓存多久算新鲜,不新鲜就算过时了(过时不代表不可用)。 后面的 must-revalidate 表示对于过时的内容,必须重新检查是否还可用(也就是 304 状态码检测)。

    不知道我对于我设置的这个值是否完全理解,我的需求是:缓存你随便保存多久,但是总是帮我 revalidate 一下就行。如果不设置为 0,浏览器可能并不会 revalidate。但是设置为 0 我又不知道浏览器会不会不要缓存总是立即删除。

    但是目前看起来不会删除,如果 revalidate 后还有效,会继续用。

以上的缓存控制只是针对文章主 HTML 本身(即 Document)。资源文件(Js/Css)我加了一个较短的 max-age。 如果换成给资源文件 URL 加上版本号的方式,理论上,可以把缓存有效期设置成永远。

本地开发的过程中,如果只是对主题本身进行了修改(而不是文章),比如样式和字体,此时需要刷新。如果没有 ETag,简单的做法是强制刷新,但是,强制刷新会使字体文件也没必要地全部重新加载、页面还会回到页首!这是非常不能忍的。不强制刷新的话,页面的滚动位置会保持一致。这对于观察样式的细微修改会很舒服的。

桃子的碎碎念 桃子 编辑