作为一名前端开发,工作基本上就是天天和浏览器打交道。那缓存这块也是前端领域离不开的话题,深入理解浏览器缓存将更有利于我们在前端中优化。
浏览器缓存又分两种,分别是强制缓存
和协商缓存
,两种缓存方式区别在于有无发起HTTP请求。
什么是浏览器缓存
浏览器向服务器获取资源(HTML页面、静态资源等)后,保存到浏览器的副本,当下一次请求同一个资源时,如果命中缓存规则,则直接使用浏览器的副本,否则重新向服务器获取新的资源。
强制缓存
当浏览器向服务器发起一个资源的HTTP请求后,会把当前资源的信息保存,再下一次继续加载该资源时,如果命中缓存规则就不会再向服务器发起HTTP请求,这种就称之为强制缓存。下面我们来看看如何能够命中强制缓存规则:
Expires
Expires
是HTTP/1.0版本提出的,当浏览器向服务器获取某项资源时,Response Header会带有Expires
字段返回,该字段内容存放的是过期的绝对时间,比如Expires:Mon, 29 Jan 2018 06:02:42 GMT
,浏览器会保存当前资源和Response Header的内容,当下次再获取同一个资源时,浏览器会先把本地时间和Expires
的时间做对比,如果当前时间还没到过期时间,则直接返回浏览器上次保存的资源,如果超过了该时间,则重新向服务器发起请求获取最新资源,并继续把当前资源和Response Header内容保存到本地。如果浏览器本地时间和服务器时间不一致的话,将直接影响缓存资源的判断。
Cache-Control
Cache-Control
是HTTP/1.1版本提出的,当浏览器向服务器获取某项资源时,Response Header会带有Cache-Control
字段返回,浏览器保存当前资源和Response Header的内容,当下次再获取同一个资源时,浏览器根据第一次的请求时间和Cache-Control
设定的有效期,计算一个过期时间,如果请求时间还没到过期时间则命中缓存规则。Cache-Control
字段存放内容相比Expires
更加丰富,常见的有Cache-Control: max-age=31536000
和Cache-Control: no-cache
。max-age
是指缓存存储的最大周期,在这个时间范围内代表缓存有效,no-cache
是值不使用任何缓存资源副本。
Cache-Control
字段可设置的内容较多,除上述两个外,还有private
、public
、no-store
等等,具体可前往HTTP协议官方文档查阅。
Cache-Control
的优先级高于Expires
,也就是说如果两者同时存在时,优先使用Cache-Control
判断缓存规则。
协商缓存
当浏览器第一次向服务器获取一个资源时,浏览器会保存资源副本和Response Header到本地,下一次向服务器请求同个资源时,服务器会根据请求的Request Header中的某些字段做比较,如果符合缓存规则,服务器会向浏览器返回一个状态304 Not Modified
表示资源相比较上一次请求时没有做修改,可以直接使用,这种就是协商缓存
If-None-Match/ETag
If-None-Match
和ETag
是成对出现的,是存放资源的唯一标识符,浏览器向服务器发起请求时,会在Request Header带上If-None-Match
,服务器接收到请求后,会和请求的资源的ETag
做比对,如果两着的值为一样,那么服务器认为这一次的资源与上一次请求的资源是一致的,返回304 Not Modified
给浏览器,通知浏览器可以直接使用缓存资源副本。如果If-None-Match
和ETag
的值不一致,服务器会继续判断If-Modified-Since
和Last-Modified
。
If-Modified-Since/Last-Modified
和上面的一样,If-Modified-Since
和Last-Modified
也是成对出现的,是存放上一次修改的时间,浏览器向服务器发起请求时,会在Request Header带上If-Modified-Since
,服务器接收到请求后,会和请求的资源的Last-Modified
做比对,如果两着的值为一样,那么服务器认为这一次的资源与上一次请求的资源是一致的,返回304 Not Modified
给浏览器,通知浏览器可以直接使用缓存资源副本。
为什么协商缓存可以利用两种类型做校验,是因为If-Modified-Since/Last-Modified
标注的时间只能精确到秒级,对于在1秒内发生多次修改的资源,则无法正确判断资源是否一致,而If-None-Match/ETag
提供的标识符则是资源每次改动则发生变化,能够更好的判断资源是否发生改动。在实际开发中,会发生资源不做变更,但是修改的时间却发生变化了,这种情况下如果只用If-Modified-Since/Last-Modified
做比对,则无法命中协商缓存,而If-None-Match/ETag
能够解决此类问题。
If-None-Match/ETag
的优先级高于If-Modified-Since/Last-Modified
,也就是说服务器接收到请求后,会先比较前者,前者不一致的情况下再比较后者。