web缓存(二)-浏览器缓存

web缓存

  • 什么是web缓存:
    • Web缓存是指一个Web资源(如html页面,图片,js,数据等)存在于Web服务器和客户端(浏览器)之间的副本。缓存会根据进来的请求保存输出内容的副本;当下一个请求来到的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是向源服务器再次发送请求。

      本篇只着重介绍浏览器缓存

  • web缓存的好处:
    • 减少网络带宽消耗
    • 降低服务器压力
    • 减少网络延迟,加快页面打开速度。
    • 。。。。。
  • web缓存政策:

    • 服务器缓存:
      • CDN缓存
      • 代理服务器缓存
      • Combo服务
    • 浏览器缓存

      • http缓存机制:
        • 本地缓存阶段
          • Cache-COntrol
          • Expires
        • 协商缓存阶段
          • Last-Modified&if-modified-since
          • ETag&If-None-Match
    • HTML5缓存思路

      • 离线存储manifest
      • 本地存储localStorage

浏览器缓存

浏览器端的缓存规则

对于浏览器端的缓存来讲,这些规则是在HTTP协议头和HTML页面的Meta标签中定义的。他们分别从新鲜度校验值两个维度来规定浏览器是否可以直接使用缓存中的副本,还是需要去源服务器获取更新的版本。

  • 新鲜度(过期机制):也就是缓存副本有效期。一个缓存副本必须满足以下条件,浏览器会认为它是有效的,足够新的:
    • 含有完整的过期时间控制头信息(HTTP协议报头),并且仍在有效期内;
    • 浏览器已经使用过这个缓存副本,并且在一个会话中已经检查过新鲜度
    • 满足以上两个情况的一种,浏览器会直接从缓存中获取副本并渲染。
  • 校验值(验证机制):服务器返回资源的时候有时在控制头信息带上这个资源的实体标签Etag(Entity Tag),它可以用来作为浏览器再次请求过程的校验标识。如过发现校验标识不匹配,说明资源已经被修改或过期,浏览器需求重新获取资源内容。

一个重要的概念

  • 缓存命中率:一个缓存的有效性是依照缓存的命中率来度量。它是根据得到数据请求次数与所有请求次数的比率。缓存命中率高意味着有很高的比率数据是从缓存中获取到数据的。

在HTTP请求和响应的消息报头中,常见的与缓存有关的消息报头有:
image

HTTP缓存机制

  • 缓存行为主要由缓存策略决定,而缓存策略由内容拥有者设置。这些策略主要通过特定的HTTP头部来清晰地表达。

  • 当一个用户发起一个静态资源请求的时候,浏览器会通过以下几步来获取资源:

    • 本地缓存阶段:先在本地查找该资源,如果有发现该资源,而且该资源还没有过期,就使用这一个资源,完全不会发送http请求到服务器;
    • 协商缓存阶段:如果在本地缓存找到对应的资源,但是不知道该资源是否过期或者已经过期,则发一个http请求到服务器,然后服务器判断这个请求,如果请求的资源在服务器上没有改动过,则返回304,让浏览器使用本地找到的那个资源;
    • 缓存失败阶段:当服务器发现请求的资源已经修改过,或者这是一个新的请求(在本来没有找到资源),服务器则返回该资源的数据,并且返回200, 当然这个是指找到资源的情况下,如果服务器上没有这个资源,则返回404。

用户操作行为与缓存

image

浏览器中的操作对缓存的影响:

  • 强制刷新 – 当按下ctrl+F5来刷新页面的时候, 浏览器将绕过各种缓存(本地缓存和协商缓存), 直接让服务器返回最新的资源;
  • 普通刷新 – 当按下F5来刷新页面的时候,浏览器将绕过本地缓蹲来发送请求到服务器, 此时, 协商缓存是有效的
  • 回车或转向 – 当在地址栏上输入回车或者按下跳转按钮的时候, 所有缓存都生效

本地缓存阶段

  1. Expires
  • 指定缓存到期GMT的绝对时间,如果设了max-age,max-age就会覆盖expires。如果expires到期需要重新请求。
  1. Cache-Control
  • Cache-Control:这个是http 1.1中为了弥补 Expires 缺陷新加入的。
  1. Expires和Cache-Control就是服务端用来约定和客户端的有效时间的。
    image

    • Expires是HTTP1.0的东西,而Cache-Control是HTTP1.1的,规定如果max-age和Expires同时存在,前者优先级高于后者
  2. Cache-Control的参数可以设置很多值,譬如
    image

  3. 用法举例:

1
2
Cache-Control: max-age=3600, must-revalidate
cache:使用本地缓存,不发生请求。

协商缓存阶段

Last-Modified/If-Modified-Since

而Last-Modified/If-Modified-Since就是上面说的当有效期过后,check服务端文件是否更新的第一种方式,要配合Cache-Control使用。

  • 比如第一次访问一个网站,会请求一个jquery文件,响应头返回如下信息:

    ![image](http://ww1.sinaimg.cn/mw690/6941baebgw1eukzzson9tj209904g74n.jpg)
    
  • 然后我在主页按下ctrl+r刷新,因为ctrl+r会默认跳过max-age和Expires的检验直接去向服务器发送请求(下文再探讨各种刷新后如何读取缓存),我们看看请求截图:

    ![image](http://ww2.sinaimg.cn/mw690/6941baebgw1eukzzrythmj20c708b756.jpg)
    
  • 请求头中包含了If-Modified-Since项,而它的值和上次请求响应头中的Last-Modified一致,我们发现这个日期是在遥远的2013年,也就是说这个jquery文件自从2013年的那个日期后就没有再被修改过了。

  • 将If-Modified-Since的日期和服务端该文件的最后修改日期对比,
    • 如果相同,则响应HTTP304,从缓存读数据;
    • 如果不相同文件更新了,HTTP200,返回数据,同时通过响应头更新last-Modified的值(以备下次对比)。

ETag/If-None-Match

  • 而ETag/If-None-Match则是上文大话中说的第二种check服务端文件是否更新的方式,也要配合Cache-Control使用。
  • 实际上ETag并不是文件的版本号,而是一串可以代表该文件唯一的字符串(Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。),
  • 当客户端发现和服务器约定的直接读取缓存的时间过了,就在请求中发送If-None-Match选项,值即为上次请求后响应头的ETag值,该值在服务端和服务端代表该文件唯一的字符串对比(如果服务端该文件改变了,该值就会变),

    • 如果相同,则相应HTTP304,客户端直接读取缓存,
    • 如果不相同,HTTP200,下载正确的数据,更新ETag值。

      image

看如上截图,

  • 与服务器约定的直接读取本地缓存的时间过了,
  • 就会向服务器发送新的请求,
  • 请求头中带If-None-Match项,该字符串值会在服务端进行匹配,很显然,并没有什么变化(看响应头的ETag值),
  • 于是响应HTTP304,直接读取缓存。
  • 或许你会发送该请求也有If-Modified-Since项,如果两者同时存在,If-None-Match优先,忽略If-Modified-Since。或许你会问为什么它优先?

  • HTTP1.1中ETag的出现主要是为了解决几个Last-Modified比较难解决的问题:

    • Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
    • 如果某些文件会被定期生成,但有时内容并没有任何变化(仅仅改变了时间),但Last-Modified却改变了,导致文件没法使用缓存
    • 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形

不能缓存的请求

  • 当然并不是所有请求都能被缓存。

  • 无法被浏览器缓存的请求:

    • HTTP信息头中包含Cache-Control:no-cache,pragma:no-cache(HTTP1.0),或Cache-Control:max-age=0等告诉浏览器不用缓存的请求
    • 需要根据Cookie,认证信息等决定输入内容的动态请求是不能被缓存的
    • 经过HTTPS安全加密的请求(有人也经过测试发现,ie其实在头部加入Cache-Control:max-age信息,firefox在头部加入Cache-Control : Public之后,能够对HTTPS的资源进行缓存,参考《HTTPS的七个误解》)
    • POST请求无法被缓存
    • HTTP响应头中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的请求无法被缓存

资料参考: