- 强缓存
- 协商缓存
- 缓存位置
- HTTP/1.0 Expires
- HTTP/1.1 Cache-Control
当 Expires 和 Cache-Control 同时存在的时候,Cache-Control 会优先考虑。
public: 客户端和代理服务器都可以缓存 private: 这种情况就是只有浏览器能缓存了,中间的代理服务器不能缓存。 no-cache: 跳过当前的强缓存,发送 HTTP 请求,即直接进入协商缓存阶段。 no-store:非常粗暴,不进行任何形式的缓存。 s-maxage:这和 max-age 长得比较像,但是区别在于 s-maxage 是针对代理服务器的缓存时间。 max-age: 过期时长
-
Last-Modified
即最后修改时间。在浏览器第一次给服务器发送请求后,服务器会在响应头中加上这个字段。 浏览器接收到后,如果再次请求,会在请求头中携带 If-Modified-Since 字段,这个字段的值也就是服务器传来的最后修改时间。 服务器拿到请求头中的 If-Modified-Since 的字段后,其实会和这个服务器中该资源的最后修改时间对比:
-
如果请求头中的这个值小于最后修改时间,说明是时候更新了。返回新的资源,跟常规的 HTTP 请求响应的流程一样。
-
否则返回 304,告诉浏览器直接用缓存。
-
ETag
ETag 是服务器根据当前文件的内容,给文件生成的唯一标识,只要里面的内容有改动,这个值就会变。服务器通过响应头把这个值给浏览器。 浏览器接收到 ETag 的值,会在下次请求时,将这个值作为 If-None-Match 这个字段的内容,并放到请求头中,然后发给服务器。 服务器接收到 If-None-Match 后,会跟服务器上该资源的 ETag 进行比对:
-
如果两者不一样,说明要更新了。返回新的资源,跟常规的 HTTP 请求响应的流程一样。
-
否则返回 304,告诉浏览器直接用缓存。
-
两者对比
在精准度上,ETag 优于 Last-Modified。优于 ETag 是按照内容给资源上标识,因此能准确感知资源的变化。 而 Last-Modified 就不一样了,它在一些特殊的情况并不能准确感知资源变化,主要有两种情况: 编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。 Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了。 在性能上,Last-Modified 优于 ETag,也很简单理解,Last-Modified 仅仅只是记录一个时间点,而 Etag 需要根据文件的具体内容生成哈希值。 另外,如果两种方式都支持的话,服务器会优先考虑 ETag。
- Service Worker
- Memory Cache
- Disk Cache
- Push Cache(加载到的资源缓存到硬盘和内存)
- 使用 Ctrl+F5 强制刷新页面时,会对本地缓存文件直接过期,然后跳过强缓存和协商缓存,直接请求服务器
- 点击刷新或 F5 刷新页面时,对本地缓存文件过期,然后带 If-Modifed-Since 和 If-None-Match 发起协商缓存验证新鲜度
- 浏览器输入 URL 回车,浏览器查找 Disk Cache,有则使用,没有则发送网络请求
对浏览器的缓存机制来做个简要的总结: 首先通过 Cache-Control 验证强缓存是否可用 如果强缓存可用,直接使用(200) 否则进入协商缓存,即发送 HTTP 请求,服务器通过请求头中的 Last-Modified 或者 ETag 字段检查资源是否更新
- 若资源更新,返回资源和 200 状态码
- 否则,返回 304,告诉浏览器直接从缓存获取资源
- 如果浏览器命中强缓存,则不需要给服务器发请求;而协商缓存最终由服务器来决定是否使用缓存,即客户端与服务器之间存在一次通信。
- 在 chrome 中强缓存(虽然没有发出真实的 http 请求)的请求状态码返回是 200 (from cache);而协商缓存如果命中走缓存的话,请求的状态码是 304 (not modified)。 不同浏览器的策略不同,在 Fire Fox 中,from cache 状态码是 304.
- 一些文件也许会周期性的更改,但是内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新 GET;
- 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说 1s 内修改了 N 次),If-Modified-Since 能检查到的粒度是秒级的,使用 Etag 就能够保证这种需求下客户端在 1 秒内能刷新 N 次 cache。
- 某些服务器不能精确的得到文件的最后修改时间。