记录下http的缓存策略

相信很多做过前端或者后台性能优化的童鞋对http缓存机制都有过了解,今天准备复习下这部分的知识。

首先开篇有两个问题抛出,即是,1.什么时候客户端需要使用缓存?2.使用缓存的规则是什么?

第一个问题,客户端请求一个文件,服务器返回的响应头会有两种方式可以判断,首先是cache-control属性值,它除了no-store之外,浏览器都会缓存文件数据,供下次使用。

其次是Expires属性值,它告诉浏览器在该过期时间值前可以使用副本(但有可能存在时间不一致问题)。以上两种方式目前用的最多的是第一种,如果二者同时出现,cache-control优先级高。

最后,HTTP响应头中如果不包含Last-Modified/Etag,也不包含Cache-Control/Expires的请求,浏览器不会缓存文件。

第二个问题,虽然满足上述缓存文件的要求,但并不意味着浏览器会直接从缓存中读取数据并使用。因为浏览器它无法确定本地缓存是否可以继续使用,或许已经过期。所以这里涉及到一个策略问题来判断使用缓存的规则,我们可以从两大维度来解读此策略:新鲜度,校验值。

对于第一个维度(新鲜度),通常http协议可以通过下面这两个属性鉴别:{Last-Midified(响应)If-Modified-Since(请求)},Last-Midified属性值是告诉浏览器当前资源的最后修改时间,那下一次浏览器再次请求该资源时候,会通过If-Modified-Since把第一次的value值带上,web服务器这边会去做检查,若传输的时间值与服务器上该资源最终修改时间是一致的,则说明该资源没有被修改过,直接返回304状态码即可。当然它有一个缺点:如果在服务器上,一个资源被修改了,但是实际内容根本没有发生改变,会因为Last-Modified时间匹配不上而返回了整个实例给客户端(即使客户端缓存里有个一模一样的资源)。

那对于第二个维度(校验值),通常http协议可以通过下面这两个属性鉴别:{ETag(响应)If-None-Match(请求)}。它可以很好解决上述维度存在不准确的问题,原理和Last-Midified类似:当第一次请求服务器上的某个资源时,服务器会通过某种算法,给资源计算得出一个唯一标识符,在把资源响应给客户端的时候,会在实体首部加上ETag一起返回给客户端,那下一次浏览器再次请求该资源时候,会通过If-None-Match把第一次的Etagvalue值带上,服务器只需要比较客户端传来的ETag跟自己服务器上资源的ETag是否一致,就能很好地判断资源相对客户端而言是否被修改过,如果服务器发现ETag匹配不上,那么直接以常规GET200回包形式将新的资源(包括新的ETag)发给客户端;如果ETag是一致的,则直接返回304告诉客户端直接使用本地缓存即可。

一般而言,当Cache-Control/Expires和Last-Modified/ETag同时返回时,前者优先级高,所以再次请求相同资源,而当该副本还在有效期时间内,浏览器是不会再向服务器通过Last-Modified或者ETag去判断资源的新旧度返304或者200,而是直接取副本200(fromcache)。所以,当一些资源有可能改动比较频繁时,设置过期时间要短,不然会发生服务器端更新了资源,浏览器因为读的是缓存而不能加载最新资源。

文章最后,附一张摘自网络上很常见的资源请求流程图:
Markdown