浏览器如何缓存资源?
首先缓存按照位置可以分为:service worker、memory cache、disk cache
memory cache
顾名思义,在内存中缓存资源。 事实上所有的请求都会被内存缓存下来,memory cache 的特点是: 时间短——tab 关闭后就会失效; 容量有限,超过容量之后缓存也会失效; 控制权在浏览器,前后端没办法干涉。
disk cache
硬盘缓存。 也可以叫做 http 缓存,因为它的缓存规则严格遵守 http 头部规范。 disk cache 的控制权在后端,disk cache 可以被分为强缓存和协商缓存。
强缓存
强缓存有两个相关字段:
Expires:
这是一个响应头,它的值是一个 http 时间戳,代表在此时间之后,资源会过期。
例如:Expires: Wed, 21 Oct 2015 07:28:00 GMT
注意:
- 如果设置了一个无效的日期,代表资源已经过期。
- 如果在 Cache-control 中设置了 max-age 或者 s-max-age ,那么 Expires 会被忽略。
Cache-control:
这是一个请求和响应中通用的消息字段,通过指定指令来实现缓存。指定指令是单向的,也就是说,请求中设置了,不一定响应中也设置。
多个指令用逗号分隔。
请求指令如下:
//[到期]缓存的最大周期,时间是相对于请求的时间
Cache-Control: max-age=<seconds>
// [可缓存性]强制要求进行协商缓存
Cache-control: no-cache
//[可缓存性]不缓存任何请求或响应的内容
Cache-control: no-store
响应指令如下:
Cache-Control: max-age=<seconds>
//[重新验证和重新加载]如果验证过期了,需要进行协商缓存
Cache-control: must-revalidate
Cache-control: no-cache
Cache-control: no-store
//[可缓存性]可以被任何对象(客户端、代理服务器)缓存
Cache-control: public
//[可缓存性]只能被单个用户缓存,不能作为共享缓存(比如代理服务器不能缓存)
Cache-control: private
协商缓存
协商缓存即条件请求,不满足条件不缓存。
Last-Modified 、If-Modified-Since 、If-Unmodified-Since
Last-Modified 是响应头,包含服务器认定的资源做出修改的时间。精确度比 Etag 低。
If-Modified-Since 、If-Unmodified-Since 在条件请求中会使用 Last-Modified 的值。
-
对于 GET、HEAD 请求,如果请求的资源从 If-Modified-Since 那个时间之后没有被修改过,就返回一个不带消息主体的 304 ,否则返回 200。
-
对于 POST 、PUT 或其他 non-safe 方法的请求,如果资源从 If-Unmodified-Since 之后被修改了,就会返回 412 错误。
Etag 、 If-Match 和 If-None-Match
Etag 是响应头,是资源的特定版本标识符,可以让缓存更高效,同时可以节省带宽。因为资源内容如果没变,web 服务器不需要发送完整的响应。
If-Match 和 If-None-Match 是请求头,值是从 Etag 中拿到的。
与 If-Modified-Since 一同使用时,If-None-Match 优先级更高。
两个例子说明 Etag 的用途:
1、POST PUT DELETE 等,返回 412 ,避免“空中碰撞”
比如用户 a 编辑 wiki 时,当前的文档内容响应中有:
Etag :"33a64df551425fcc55e4d42a148795d9f25f89d4"
更改了文档,保存时, POST 请求将之前的 Etag 放入 If-Match 中,用来检查是否保存的是最新版本:
If-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
如果不匹配,意味着文档已经被另一个人编辑了,抛出 412 错误。
2、GET HEAD ,判断客户端资源是否可用
如果用户请求里带着 Etag 再次访问给定的 url ,被提示资源过期了且不可用,客户端就把 Etag 放在 If-None-Match 中:
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
服务器将客户端的 If-None-Match 带来的值与当前资源的 Etag 进行比较,如果匹配,服务器将返回不带任何内容的 304 状态码。
service worker
memory cache 无法控制,disk cache 只能通过设置头部信息,由浏览器内部进行判断。
但通过 service worker 的 api ,我们可以控制缓存,包括数据、静态资源、甚至拦截网络请求。
service worker 操作的缓存可以在 application -> cache storage 中看到,除非容量超过限制或者手动清除了,否则永久存在。