前言
在web
页面优化中,缓存是用来优化的一个重要的手段。当利用好缓存之后,会让页面的加载速度大大提高。并且当有缓存存在时,也会减少对服务器的请求和静态资源的请求,对流量和cdn
的消耗都有很大的好处。接下来就来熟悉下浏览器使用的缓存有哪些,区别是什么?
浏览器缓存
当浏览器向服务器请求资源时,当发现本地浏览器有缓存时,就会直接从缓存中取资源,浏览器并不会给服务器发真正的请求。简单说下缓存的查找机制:
- 当浏览器第一次发请求给服务器时,此时的浏览器由于是第一次和服务器交互,所以没有从服务端拿到过数据资源,此时浏览器本地就没有缓存数据,于是就直接访问服务器,然后服务器接收到请求之后就把资源返回给浏览器,然后响应码为
200
,浏览器接收到资源后,就把资源和对应的响应头一起缓存下来。 - 当浏览器在发请求给服务器时,浏览器会检查下本地的强缓存也就是上次请求中携带
Cache-Control
的数据。如果资源没有过期就使用缓存中的资源,不在去服务器端请求数据。 - 如果浏览器没有命中缓存或者命中的缓存已经过期,浏览器就会把请求发送给服务器,进入协商缓存阶段。
浏览器缓存分为强缓存和协商缓存,当客户端请求某个资源时,会按照以下步骤进行缓存查询
- 首先先根据资源的
http header
判断它是否命中强缓存,先检查Cache-Control
,如果命中就会直接从本地缓存中取资源,不会发请求到服务器 - 当强缓存没有命中,就会进入协商缓存阶段,浏览器会发请求到服务器,服务器端通过request header验证资源是否命中协商缓存,如果命中协商缓存,服务器将请求返回,但是不会返回数据,状态码为304告诉浏览器在本地缓存中取资源。
- 当协商缓存也没有命中的时候,服务端就会发资源给客户端
- 当强制刷新网页时,比如
ctrl+f5
,就会直接跳过强缓存和协商缓存,直接请求服务器拿到资源 - 普通刷新只是跳过强缓存,但是会检查协商缓存
强缓存
Expires
Expires
是HTTP/1.0
出现的头信息,同样是用于决定本地缓存的头,它是一个绝对时间,只要发送请求的时间s是在Expires
之前,那么本地缓存始终有效,否则就会去服务器发送请求获取最新的资源,如果同时出现Cache-Control:max-age
和Expires
,那么max-age
的优先级更高。
Cache-Control
Cache-Control
是http
缓存中最重要的头,它是HTTP/1.1
中出现的,具体有以下几个值
no-cache
不使用强缓存,会进入协商缓存阶段,如何协商缓存可用,则直接使用缓存资源
no-store
直接禁止浏览器缓存,每次都是从服务器拿到新的资源
public
可以被所有用户缓存,包括浏览器和cdn等中间代理服务器
private
只允许浏览器缓存,不允许cdn等中间代理服务器缓存
max-age
从当前请求开始,允许缓存可用的最长时间
must-revalidate
当缓存过期时,需要去服务器校验缓存的有效性
协商缓存
一般什么情况下回去查询协商缓存呢?
- 没有
Cache-Control
和Expires
Cache-Control
和Expires
过期了Cache-Control
的属性设置为no-cache
时
当请求的时候符合以上条件时,浏览器就会进入协商缓存阶段,如果命中就返回304从缓存中取资源。如果没有命中缓存,服务器就直接发送新的资源状态码为200。负责协商缓存的头信息是Last-Modified/If-Modified-Since
和ETag/If-None-Match
Last-Modified
(值为资源最后更新时间,随服务器response
返回,即使文件改回去,日期也会变化)If-Modified-Since
(通过比较两个时间来判断资源在两次请求期间是否有过修改,如果没有修改,则命中协商缓存)ETag
(表示资源内容的唯一标识,随服务器response
返回,仅根据文件内容是否变化判断)If-None-Match
(服务器通过比较请求头部的If-None-Match
与当前资源的ETag
是否一致来判断资源是否在两次请求之间有过修改,如果没有修改,则命中协商缓存
Last-Modified / If-Modified-Since
当浏览器发出请求时,服务器会把资源的最新修改时间通过Last-Modified
头信息携带返回给浏览器进行缓存,然后当浏览器再次请求时,就会在If-Modified-Since
中携带服务器上次返回的时间,然后服务器将这个时间与最新资源修改的时间进行对比,如果等于或者大于最新时间,那么缓存就是有效的,返回304
.如果不是则直接返回最新资源并且更新Last-Modified
头信息
但是这个虽然可以判断缓存资源是否有效,但是有两个问题
- 精度存在误差因为
Last-Modified
的时间精度为妙,如果时在1
秒内发生的更新,那么判断就不准确了 - 准确度也有误差比如一个文件修改了然后又被还原了,其实浏览器的缓存还是可以用的,但是修改时间改变了,这里的缓存判断也不准确了
ETag / If-None-Match
为了解决精度和准准确度的问题,提供了ETag
的方式。通过文件哈希值来准确判断缓存。
当浏览器请求服务器时,服务器向响应头中添加Etag
字段,它的值为该资源的哈希值。浏览器再次请求服务器时会通过If-None-Match
携带上次缓存的ETag
值。然后服务器把当前的文件资源的哈希值和携带过来的哈希值进行比较,如果两个值相同,就是资源没有改变返回304
不然的话就会直接返回新的资源并更新ETag
值
当然这个方式也有一些缺点
- 计算成本生成哈希值是个比较大的操作
- 计算误差不同服务器采用不同算法生成得哈希值可能不一样
缓存得优先级
强缓存高于协商缓存,协商缓存中ETag
高于Last-Modified