前言
web缓存可分为:浏览器缓存、服务器缓存、数据库缓存、CDN缓存。 而浏览器缓存又分为:http缓存、localStorage、sessionStorage、cookie等。 对于http缓存又分为强缓存和协商缓存。
使用http缓存的作用
- 减少网络带宽消耗。当http缓存副本被使用时,只会产生极小的网络流量,可以有效的降低运营成本
- 降低服务器压力,给网络资源设定有效期后,用户可以重复使用本地的缓存,减少对源服务器的请求,间接降低服务器的压力
- 减少网络延迟,加快页面打开速度,对于最终用户,缓存的使用能够明显加快页面打开速度,达到更好的体验
强缓存
对于强制缓存,服务器响应的header中会用两个字段来表明,expires和cache-control
-
expires:值为服务端返回的数据到期时间,当再次请求时的请求时间如果小于返回的此时间,则直接使用缓存数据。但由于服务端时间和客户端的时间可能有误差,这也将导致缓存命中的误差,并且,expires是http/1.0的产物,故现在大多数使用cache-control替代。
-
cache-control有很多属性,不同的属性代表的意义也不同。
- private:客户端可以缓存
- public:客户端和代理服务器都可以缓存
- max-age=t:缓存内容将在t秒后失效
- no-cache:实际的意思并不是不允许缓存,而是可以缓存,但在使用之前必须去服务器验证是否过期,是否有最新的版本
- no-store:所有内容都不会缓存,用于某些变化非常频繁的数据。例如秒杀页面
- must-revalidate:如果缓存不过期就可以继续使用,但过期了如果还想用就必须去服务器验证
举例说明:去超市买西瓜。no-store:买来的西瓜不允许放进冰箱,要么立刻吃掉,要么立刻扔掉;no-cache:可以放进冰箱,但吃之前必须问问超市有没有更新鲜的,如果有,就去吃超市里的。(看来超市遇到大客户了);must-revalidate:可以放进冰箱,保鲜期内可以吃,过期了就要问问超市让不让吃(看来超市又遇到了个傻子);
另外:Ctrl+F5的“强制刷新”它其实是发起了“cache-control: no-cache”,含义和“max-age=0”基本一样;
协商缓存
协商缓存需要对比判断是否可以使用缓存。浏览器第一次请求数据时,服务器会将缓存标识与数据一起响应给客户端,客户端将他们备份至缓存中。再次请求时,客户端会将缓存中的标识发送给服务器,服务器根据此标识来判断。若未失效,返回304状态码(not modified),浏览器拿到此状态码就可以直接使用缓存数据了。
last-modified / if-modified-since
last-modified:是一个响应首部字段,包含服务器认定的资源最后的修改时间。
if-modified-since:浏览器再次请求服务器的时候,请求头会包含此字段,后面跟着之前请求所获得的最后修改时间,该字段只能用在get或head请求中。服务端收到请求头发现有if-modified-since,则与被请求资源的最后修改时间进行对比,如果一致则返回304,此时客户端只需要从缓存中读取即可。
etag / if-none-match
etag:是一个响应首部字段,它是根据实体内容生成的一段hash字符串,标识资源的状态,由服务端产生。
if-none-match:是一个条件式的请求首部。如果请求资源时在请求头加上这个字段,值为之前服务端返回的资源上的etag,当且仅当服务器上没有任何资源的etag值能与此值匹配时,服务器才会返回带有所请求资源的实体的200响应。否则服务器会返回不带实体的304响应;etag优先级高于last-modified。
etag相较于last-modified的优势
- 某些情况下服务器无法获取资源的最后修改时间
- 资源的最后修改时间改变了,但是内容没有变,那么此时last-modified就不能有效的使用缓存
- 如果资源修改非常频繁,在秒以下的时间进行了修改,而last-modified只能精确到秒,那么此时服务器所做的处理可能会是有误的
强缓存与协商缓存的区别
强缓存命中的话不会发请求到服务器,协商请求一定会发请求到服务器,通过资源的请求首部字段验证资源是否命中协商缓存,如果协商缓存命中,服务器会将这个请求返回,但是不会返回这个资源的实体,而是通知客户端可以从缓存中加载这个资源(http状态码为304,not modified)。
浏览器不同刷新的区别
- 浏览器地址栏中输入url,回车,浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿(最快)
- F5刷新,告诉浏览器,别偷懒,好歹去服务器看看这个文件是否过期了。于是浏览器就胆胆襟襟的发送请求并带上if-modified-since
- Ctrl+F5刷新,告诉浏览器,你先把你缓存中的文件删了,然后再去服务器中请求个完整的资源下来,于是客户端完成了强制更新的操作。