强缓存

当发起HTTP请求时,不会向服务器进行请求,只要当前时间在缓存有效期内,则直接从客户端缓存中获得,当缓存过期之后,才会真正想服务器发起请求重新获得资源。

强缓存有什么作用:

1)对于页面上耗费带宽且不常更改的资源,一旦下载,可直接将其缓存在浏览器,用户再次使用,可大大降低加载等待时间,提升用户体验;
2)针对弱网或网络不稳定的用户,强缓存可预留出足够的带宽,让给主资源请求,防止因主资源请求超时导致页面无法正常显示。

弊端

强缓存的优点就是,只要客户端存在有效期内的资源,就不再从服务端获取资源,而他的优点也正是他的弊端,如果服务器资源更新了,或者修正了一个bug,而强制缓存时间太长,就会造成客户端信息更新落后的问题,怎么办呢?能不能有一个这样的解决方法:每次请求资源,先问问服务器:我需要重新拿资源吗?服务器通过标识对比,缓存数据没有更改,缓存时间也没过期,然后告诉客户端,继续用存储的数据吧,我这没啥变更。这样既解决了缓存问题,也解决了更新问题。虽然依然是每次都发送请求,请求数量没减少,但是却可以降低数据量传输。这样的方案叫协商缓存。

小结

强缓存下,无论是从客户端获取的资源还是从服务器端获取的更新资源,在获取成功时,返回的状态码都是200,唯一能区分的,是跟在状态码后面有没有from memory cache 或 from disk cache.在有效期内,只有第一次会真正向服务器发送请求获取数据

协商缓存

response header里面的设置

  1. etag: '5c20abbd-e2e8'
  2. last-modified: Mon, 24 Dec 2018 09:49:49 GMT

etag:每个文件有唯一一个,资源变更则etag变更。是一个文件hash,加上的目的就是为了对比客户端和服务端是否一致,判断是有更新,不一致则认为是更新了,一致则认为未更改。 last-modified:文件的修改时间,精确到秒。
也就是说,每次请求返回来 response header 中的 etag和 last-modified,在下次请求时在 request header 就把这两个带上,服务端把你带过来的标识进行对比,然后判断资源是否更改了,如果更改就直接返回新的资源,和更新对应的response header的标识etag、last-modified。如果资源没有变,那就不变etag、last-modified,这时候对客户端来说,每次请求都是要进行协商缓存了,即:
发请求—>看资源是否过期—>过期—>请求服务器—>服务器对比资源是否真的过期—>没过期—>返回304状态码—>客户端用缓存的老资源。
这就是一条完整的协商缓存的过程。
当服务端发现资源真的过期的时候,会走如下流程:
发请求—>看资源是否过期—>过期—>请求服务器—>服务器对比资源是否真的过期—>过期—>返回200状态码—>客户端如第一次接收该资源一样,记下它的cache-control中的max-age、etag、last-modified等。
所以协商缓存步骤总结:
请求资源时,把用户本地该资源的 etag 同时带到服务端,服务端和最新资源做对比。 如果资源没更改,返回304,浏览器读取本地缓存。 如果资源有更改,返回200,返回最新的资源。

为什么要有etag?

你可能会觉得使用last-modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要etag呢?HTTP1.1中etag的出现(也就是说,etag是新增的,为了解决之前只有If-Modified的缺点)主要是为了解决几个last-modified比较难解决的问题:
1)一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新get;
2)某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),if-modified-since能检查到的粒度是秒级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);
3)某些服务器不能精确的得到文件的最后修改时间。

小结

协商缓存首次请求成功会返回状态码200,在接下来,如果文件未更改,则会返回状态码为304,因此可以通过判断状态码值来确定资源是重新更新的还是来自缓存。另外,由于标识资源是否有效的last-modify和etag都是由服务端确定,因此,协商缓存不会受制于本地系统时间的更改。

当协商缓存与强缓存同时存在时 强缓存的优先级更高
浏览器缓存的理解