TIP浏览器缓存是浏览器在本地磁盘对用户最近请求过的资源进行存储,当再次访问统一资源时,就可以直接使用缓存,可以减少与服务器的数据传输,减小服务器的负担,提高页面响应速度等
请求过程
TIP浏览器在第一次请求后缓存资源,再次请求时,会进行下面两个步骤:
- 浏览器发起对于某资源的请求时,会先检查本地是否存在缓存,如果存在则通过
expires
和cache-control
检查缓存是否有效,如果命中缓存且缓存未过期,则不会向服务器发起请求,直接使用缓存资源- 若未命中本地缓存,浏览器就会向服务器发送一个协商请求,通过
Last-Modified-Since
或者IF-None-Match
(这两个字段的值,分别是第一次请求返回的Last-Modified/Etag
)来向服务器验证是否命中协商缓存 :
- 如果命中,服务器会返回304状态码,且此次响应不会返回资源内容,浏览器直接使用缓存
- 如果未命中,服务器则会返回200状态码,并返回资源的实际内容,同时更新
header
中的字段
强缓存:package:
TIP 强缓存是通过
Expires
和Cache-Control
来控制缓存在本地的有效期的
Expires
TIP
Expires
是HTTP1.0
提出的一个表示资源过期时间的request header
,它描述的是一个绝对时间,由服务器返回。Expires
受限于本地时间,如果修改本地时间,可能会造成缓存失效。对于一个资源的请求,如果在Expires
内,则浏览器会直接使用缓存,不请求服务器 格式如下:
Expires: Sun, 14 Jun 2020 02:50:57 GMT
Cache-Control
TIP
Cache-Control
出现于HTTP1.1
,优先级高于Expires
,它描述的是相对时间,请求头和响应头都支持这个字段,用来定义缓存策略 格式如下:
Cache-Control: max-age=300
TIP
Cache-Control: no-store
: 禁止浏览器缓存数据,每次请求资源都会向服务器要完整的资源Cache-Control: no-cache
: 不使用本地缓存,需要使用协商缓存Cache-Control: public | private
:
private
: 默认值。表示只能应用于浏览器私有缓存中public
: 表示该响应可以被任何中间人,中间代理,CDN
等缓存。Cache-Control: max-age=xxx
: 响应的最大过期时间,单位是s。表示资源能够被缓存的时间(即保持新鲜的最大事件),max-age
是距离请求发起的时间的秒数Cache-Control: must-revalidate
: 当使用了must-revalidate
指令,那就意味着缓存在考虑使用一个陈旧的资源时,必须先验证它的状态,已过期的缓存将不被使用。在正常情况下是没有必要使用这个指令的,因为在强缓存过期的情况下会进行协商缓存,但是HTTP
规范是允许客户端在某些特殊情况下直接使用过期缓存的,比如校验请求发送失败的时候,还比如有配置一些特殊指令stale-while-revalidate
、stale-if-error
等的时候,must-revalidate
指令就是让缓存在过期后的任何情况下都必须重新验证。
协商缓存:package:
TIP 当浏览器对某个资源的请求没有命中强缓存,就会发送一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的状态码为
304(Not Modified)
,该请求不携带实体数据;若未命中,则返回200状态码
并携带资源实体数据。 协商缓存主要利用的是
Last-Modified、IF-Modified-Since
和ETag、IF-None-Match
这两对字段来控制的。
Last-Modified、IF-Modified-Since
TIP 在
HTTP1.0
引入。Last-Modified
表示本地文件的最后修改日期,浏览器会在请求头上加上IF-Modified-Since
(也就是上次相应的Last-Modified
的值),来询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来。 但是,如果在本地打开缓存文件,就会导致
Last-Modified
被修改,所以在HTTP1.1
出现了ETag
ETag、IF-None-Match
TIP
ETag
是服务器为资源生成的唯一标识串,资源发生变化会导致Etag
变化,跟最后修改时间没有关系,所以ETag
可以保证每个资源是唯一的。IF-None-Match
的请求字段会将上次返回的ETag
发送给服务器,来询问该资源的ETag
是否有更新,如果有变动就会发送新的资源回来。
ETag
的优先级比Last-Modified
高,在以下类似情况,应该优先使用ETag
:
- 一些文件也许会周期性的更改,但是他的内容并不改变,比如仅仅改变的修改时间,这个时候我们并不希望客户端认为这个文件被修改了,而重新
GET
- 某些文件修改非常频繁,比如在秒以下的时间内进行修改,例如
1s
内修改了N
次,If-Modified-Since
能检查到的粒度是秒级的,这种修改无法判断- 某些服务器不能精确的得到文件的最后修改时间