# 缓存实践

原文:Caching best practices & max-age gotchas (opens new window)

缓存大多分为两种模式:

  • 不可变内容 + 很长的 max-age
  • 可变内容,总是需要经过服务器重新验证

# 不可变内容 + 很长的 max-age

Cache-Control: max-age=31536000
1

此种模式:

  • 一个固定的 URL 指向的内容永远不会变,要变就是直接变 URL 。
  • 浏览器或CDN将这个资源缓存一年不会有任何问题
  • 缓存内容的时间小于 max-age 时(也就是缓存未失效),可以直接使用,不需要询问服务器来验证它。

适用情况:

<script src="/script-f93bca2c.js"></script>
<link rel="stylesheet" href="/styles-a837cb1e.css" />
<img src="/cats-0e9a2ef4.jpg" alt="" />
1
2
3

每一个资源文件经过打包后,会根据内容生成一个唯一的 hash 值,如果文件内容有变化,则这个 hash 值会变化,也就是访问的 URL 就会变化,一个固定的 URL 指向的内容是肯定不会有变化的。

然而,这种模式不适用于文章和博客文章。它们的 URL 不能变,也就是不能使用文件 hash 值作为 URL,但内容是需要改变更新的。比如基本拼写和语法错误,修改之后,必须保持原来的 URL。

# 可变内容,总是需要经过服务器重新验证

Cache-Control: no-cache
1

此种模式:

  • 一个固定 URL 的内容可能会改变
  • 所有缓存文件在使用时,都需要经过服务器校验是否有更新

注意: no-cache 并不意味着“不缓存”,它意味着在使用缓存资源之前必须由服务器来检查 (revalidate)。no-store 才是告诉浏览器不要缓存它。此外,must-revalidate 并不意味着“必须重新验证”,它的意思是,如果本地资源缓存时间小于提供的 max-age,则可以使用它,否则必须重新验证。

在这种模式中,可以在响应头种,添加 ETag (你选择的版本ID) 或 Last-Modified 。下次客户端获取资源时,会在请求头中,通过 If-None-Match 带上上一次获取的 ETag ,或通过 If-Modified-Since 带上上一次获取的 Last-Modified 来询问服务器。如果服务器校验没有发现更新,则会告诉客户端:“你的资源已经是最新的了,直接使用就行了”。

如果服务端无法发送 ETagLast-Modified,那么服务端总是会返回完整的文件资源。

这种模式,总是涉及到网络连接,所以它不如前一种模式好,因为前一种模式在缓存未失效时,可以完全不使用网络。