跳到主要内容

http 缓存

缓存后台是如何实现更新的

CDN 或 nginx 在后台刷新文件路径,或者更小文件的 header

年末 nginx 一般需要统一配置所有版本 302 至最新版

强缓存过期后默认会进入协商缓存

我们应该怎么选择强缓还是弱缓?

  • 强缓 强缓存资源一般名称就带有 hash 值(或者版本号),配置一个比较长的过期时间

    想更新缓存,那就废弃原引入文件,换个新 hash 名称文件就行

    适用于不经常更新的资源


  • 弱缓 弱缓我们利用的是浏览器内置和 http 字段,再交给服务器做判断 算是一种让你自定义是基于时间还是资源内容的缓存策略

    适用于经常更新的资源

    但是前端所有资源除了 public 静态资源,理论上都可以使用 hash,看你利用不利用吧

缓存全流程

如果不返回 304 一定返回 200 请求原资源并更新协商缓存

说一下 http 缓存

字段优先级(如果有)

  • Cache-Control: max-age
  • Expires
  • Etag
  • Last-Modified

对于强缓存场景,max-age 要比 expires 高

Expires

Expires: Tue,17 Dec 2019 07:0:44 GMT

也可以用 Max-age 有效期,

Cache-Controll: max-age=3s 如果在 Cache-Controll 响应头设置了 max-age 或者 s-max-age,那么 expires 头会被忽略

强缓存(与 expires 相关)

作为强缓存,未过期不会请求服务器!除非过期

服务器开启强缓存,客户端会将第一次请求响应的资源、响应头中的 expires 字段保存在本地,其中 expires 字段设置了强缓存资源的过期时间。当后续客户端再请求资源时,会对比本地时间与 expires 过期时间,如果过期,则需要重新向服务器发起对资源的请求,否则直接使用本地保存的资源。

协商缓存(与 etag last-modified 相关)

举个栗子,服务器开启协商缓存,客户端会将第一次请求响应的资源保存在本地,并将资源版本信息(响应头 E-Tag= 111、Last-Modified = 2018.6.3 )保存在浏览器缓存表中,客户端第二次请求时会先请求浏览器缓存表中的缓存信息,在请求头中加入字段(If-None-Match = 111、If-Modified-Since = 2018.6.3),服务器获取之后比对 E-Tag、Last-Modified-Since 字段,若一致则返回 304 代码,客户端收到 304 后,直接使用本地缓存,否则返回新资源(走 200),客户端将新资源保存在本地,并将新 E-Tag = 112、Modified-Since = 2018.6.8 存入浏览器缓存表。

Cache-Controll 能影响整个缓存策略

no-store(禁所有缓存)

作为 cache-controll 的值,因此比 expires 等优先级高

永远都不要在客户端存储资源,永远都去原始服务器去获取资源。

不进行强制缓存和协商缓存,直接拉取最新的资源。资源不缓存到本地。

no-cache(禁强缓存)

可以在客户端存储资源,每次都必须去服务端做新鲜度校验,来决定从服务端获取新的资源(200)还是使用客户端缓存(304)。也就是所谓的协商缓存。

使用 no-cache 的目的就是为了防止从缓存中获取过期的资源

其他(支持强缓存)


一般情况下对于 index.html 或者现代构建环境下不加 hash 的静态资源都需要设置 Cache-Control: no-cache,用来强制每次在服务器端的新鲜度校验。

相当于

Cache-Control: max-age=0, must-revalidate

max-age

设置强制缓存的时间,单位 s。资源会缓存到本地

Cache-Control: max-age=315360000
使用场景:CDN(一般永远不变)
效果:缓存10年

Cache-Control: max-age=31536000
使用场景:比如图片资源(几乎不变)
效果:缓存1年

Cache-Control: max-age=2592000
使用场景:比如js,css资源(按月迭代,较少频率改变)
效果:缓存1月

Cache-Control: no-cache
使用场景:webpack工程的 SPA单页面的入口 index.html(可能频繁改变)
效果:每次都要发起协商缓存,去询问资源是否变更,无变更则304重定向

private

如果有这个字段 比如:Cache-Control: private, max-age=360000,意思:中间层(代理)或者说 CDN 不缓存此资源,使 CDN 失效,每次只能访问源服务器

public

CDN 可以缓存

缓存优先级

请求一个资源时,会按照优先级(Service Worker -> Memory Cache -> Disk Cache -> Push Cache)依次查找缓存,如果命中则使用缓存,否则发起请求

按优先级从高到底,浏览器的资源会被缓存在以下位置:

Service Worker

Service Worker 是浏览器独立于网页在后台运行的脚本,它有着独立的 js 运行环境,协助前端页面完成需要在后台悄悄执行的任务,它的缓存是永久性的。除非手动调用 api 或者容量超过限制才会被浏览器清除。 经过 Service Worker 的 fetch() 方法获取的资源,即便它并没有命中 Service Worker 缓存,甚至实际走了网络请求,在 Chrome 的 Network 面板也会被标注为 from ServiceWorker。

可以用来拦截缓存资源

Memory Cache

几乎所有的网络请求资源都会被浏览器自动加入 memory cache,即缓存在内存中。一般情况下,浏览器 tab 关闭,该页面相关的 memory cache 就会失效。虽然 memory cache 是无视 HTTP 请求头的,但是 no-store 除外。在设置了 Cache-Control: no-store 的情况下,该资源不进行任何缓存。

Disk Cache(HTTP cache)

HTTP 协议头的缓存相关字段,限定的都是 disk cache 相关的缓存策略,它是持久存储,实际存在于文件系统中的,而且它允许相同的资源跨会话,甚至跨站点的情况下使用。浏览器会根据自己的算法自动清理最老的和最可能过时的。

Push Cache

Push Cache 是 HTTP2 中的内容,当以上三种缓存都没命中的时候,才会被使用。它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在 Chrome 浏览器中只有 5 分钟左右,同时它也并非严格执行 HTTP 头中的缓存指令

etag 和 last modified

Last-Modified 缺点:以秒为单位,如果不超过一秒内不会检测到资源发生的改变

资源走完一个生命周期循环回到原来的状态

其实没发生变化,但也会被判断为发生改变

Etag 缺点:负载均衡时,不同服务器上 Etag 值不一样,此时最好不用 Etag