HTTP的缓存实践

HTTP的缓存实践

参考资料

缓存的资料中,难免有一些描述不精确的地方,会误导人,需要自己结合更多的靠近规范的解释去甄别,下述两篇中,第一篇写的非常好,第二篇可以作为辅助:

最佳推荐:浏览器缓存策略之扫盲篇

IMWeb前端博客: HTTP缓存控制小结

前情

首部字段分为:通用首部、请求首部、响应首部、实体首部。

目前主流的HTTP版本是HTTP/1.1,部分网站的版本已经是HTTP/2。

字段

Pragma

  • 是HTTP/1.0的通用首部字段

  • 仅有一个no-cache的值

  • 含义是使用之前必须去服务器校验当前版本是不是最新的

  • 这个字段的作用对象是服务器,因为Pragma is not specified for HTTP responses ,只能在请求头传递给服务器

  • 这个字段的控制权归浏览器,即浏览器作为发起者,决定了是否在请求头部是否加上该字段

  • 该字段已经被抛弃,但为了向下兼容还是保留了它

Expires

  • 是HTTP/1.0的实体首部字段

  • 值是GMT格式的时间值

  • 含义是资源到什么时间之前都是有效的

  • 这个字段的作用对象是浏览器,因为The HTTP Expires header is a response-type header,通常作为相应头传递给浏览器

  • 这个字段的控制权是服务器,即服务器发送给浏览器,浏览器依据它来决定重新请求网页时,是否发送新的请求到服务器

Cache-Control

Last-Modified 和 ETag

  • Last-Modified是实体首部字段,ETag是响应首部字段

  • 他们都是在响应头出现

  • 其中Last-Modified描述了资源最后一次修改时间,ETag(Entity Tag)描述了资源的唯一标识

  • ETag比Last-Modified更精确,因为文件可能在同一秒内被修改了Last-Modified是同一个值,同样修改多次可能内容不变

  • ETag又分为强弱两种模式,强模式字符级别完全相同,弱模式的值前面有个w/的标记,标识语义上没有变化

If-Modified-Since 和 If-None-Match

  • If-Modified-Since 和 If-None-Match 都是请求首部字段

  • 他们会作请求头传递给服务器,值对应的是 Last-Modified 和 ETag 的值

  • 服务器会基于最新的生成的值与If-Modified-Since/If-None-Match的值进行对比,资源过期返回200,否则返回304 Not Modified。

If-Unmodified、If-Match、If-Range

缓存策略

个人博客为例

博客内容是基于Webpack打包的

首次打开网页,第一个请求访问的是html文件,通常来说响应头不会指定Cache-Control:max-age=xxx 或 Expires 这样的字段。

因为网页作为入口文件,必须是最新的,也就是说,不能用强缓存,而是返回ETag 和 Last-Modified。

相应的,图片、js、CSS文件也都是在请求头通过ETag 和 Last-Modified来进行缓存控制的。

在地址栏点击刷新,请求html的时候默认会携带 If-Modified-Since 和 If-None-Match给服务器。

服务器校验发现本地缓存的版本是最新的,返回304,直接利用使用本地的缓存内容即可。

相应的,本地的被依赖的图片、JS、CSS,也会因为HTML使用的是缓存而使用缓存,因此是200 from memory cache 或者 200 from disk cache。

  • 200 from memory cache:资源在内存当中,一般脚本、字体、图片会存在内存当中
  • 200 from disk cache:在磁盘当中,一般非脚本会存在内存当中,如css等

浏览器的刷新行为

  • 浏览器地址前进、后退,在入口的html文件这一级,就会使用强缓存,200 from disk cache
  • 浏览器地址栏回车 或 点击刷新按钮,Command+R(Mac下)刷新,入口文件(注资源)会走协商缓存,派生资源优先强缓存
  • Command+Shift+R 刷新,所有资源都会从服务器请求最新的

补充:

最佳推荐:浏览器缓存策略之扫盲篇明确分类了上述三种行为对应的操作,并且介绍了在Chrome和Firefox上的差异,感兴趣可以实践。

最佳实践

引用最佳推荐:浏览器缓存策略之扫盲篇

  • 不要缓存 HTML,避免缓存后用户无法及时获取到更新内容。
  • 使用Cache-Control和ETag来控制 HTML 中所使用的静态资源的缓存。一般是将Cache-Control的max-age设成一个比较大的值,然后用ETag进行验证。
  • 使用签名或者版本来区分静态资源。这样静态资源会生成不同的资源访问链接,不会产生修改之后无法感知的情况。