当前位置: 首页 > Web前端 > HTML5

HTTPNegotiationCacheVSStrongCache

时间:2023-04-05 00:02:29 HTML5

之前,我只能描述浏览器缓存的大概思路,无法描述深层次的原理;在前端的两次面试中,我终于倒下了。为了泄愤,查阅了一些资料,终于对它有了更深的了解,废话不多说,我们来看看关于浏览器缓存的那些事。如有不妥之处,还请不吝赐教。本文主要讲解浏览器端的缓存。缓存的作用不言而喻,可以极大地提升网页性能和用户体验。1.浏览器缓存cache。第一次获取资源后,根据返回信息告诉如何缓存资源。它可能使用强缓存,也可能告诉客户端浏览器它是协商缓存,这需要根据响应的头部内容来确定。下面两张图用来描述浏览器的缓存是如何工作的,让大家有个大概的了解。当浏览器发出第一个请求时:当浏览器发出后续请求时:从上图可以看出,浏览器缓存有两种,分别是强缓存(也叫本地缓存)和协商缓存。发生后,再次请求时:浏览器请求资源时,会先获取资源缓存的头部信息,判断是否命中强缓存(cache-control和expires信息)。如果命中,则直接从缓存中获取资源信息。包括缓存头信息;该请求根本不会与服务器通信;firebug下可以查看强缓存资源返回的信息,比如本地firebug查看的强缓存js文件没有命中强缓存,浏览器就会向服务器发送请求,而该请求会携带第一次请求返回的缓存头字段信息(Last-Modified/If-Modified-Since和Etag/If-None-Match),服务器会使用请求中的相关头信息来比较结果查看协商缓存是否命中;如果命中,服务器返回新的响应头信息更新缓存中相应的头信息,但不返回资源内容,会通知浏览器可以直接从缓存中获取;否则返回最新的响应头信息资源内容强缓存和协商缓存的区别如下表:获取资源表单状态码向服务器发送请求强缓存get200fromcache(从缓存中)没有,直接getnegotiationcachefromcacheGet304fromcache(notmodified)是的,顾名思义,服务端用来通知缓存是否可用2.强缓存相关的Header字段强缓存上面已经介绍过了,获取资源直接从缓存中获取,无需通过服务器;与强缓存相关的头字段有:二:expires,这是http1.0的规范;其值为绝对时间GMT格式时间字符串,如Mon,10Jun201521:31:12GMT,如果发送请求的时间在expires之前,则本地缓存一直有效,否则发送请求到服务器获取资源cache-control:max-age=number,这是http1中出现的header信息。判断,是一个相对值;资源的第一次请求时间和Cache-Control设置的有效期计算出一个资源过期时间,然后比较这个过期时间和当前请求时间,如果请求时间在过期时间之前,就可以命中缓存,否则不起作用;除了这个字段,cache-control还有以下比较常用的设置值:no-cache:不使用本地缓存,需要使用缓存协商,先和服务器确认返回的response是否有变化,如果有先前响应中的ETag,将在发出请求时与服务器进行验证。如果资源没有改变,可以避免重新下载。no-store:直接禁止浏览器缓存数据。用户每次请求资源时,都会向服务器发送一个请求,每次都会下载完整的资源。public:可以被所有用户缓存,包括终端用户和CDN等中间代理服务器。private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器缓存。  注意:如果cache-control和expires同时存在,则cache-control的优先级高于expires3。协商缓存相关头字段由服务端判断缓存资源是否可用,因此客户端和服务端需要通过某种标识进行通信,以便服务端判断请求的资源是否可以缓存和访问.这主要涉及以下两组头域。这两组搭档是成对出现的,即第一个请求的响应头中带有某个字段(Last-Modified或Etag),后续请求会携带相应的请求字段(If-Modified-Since或If-None-Match),如果响应头没有Last-Modified或者Etag字段,那么请求头中就没有对应的字段。Last-Modified/If-Modified-Since的值都是GMT格式的时间字符串。具体过程:浏览器第一次向服务器请求资源,服务器返回资源并添加到响应头Last-Modified头中,该头表示该资源在服务器上的最后修改时间。当浏览器再次向服务器请求该资源时,在请求的头部添加If-Modified-Since的头部。这个header的值是最后一次请求时返回的Last-Modified值当服务器再次收到资源请求时,根据浏览器发送的If-Modified-Since和最后一次修改判断资源是否发生变化服务器上资源的时间。如果没有变化,则返回304NotModified,但不会返回资源内容;如果有变化,资源内容会正常返回。当服务器返回304NotModified响应时,Last-Modified头不会被添加到响应头中,因为既然资源没有改变,Last-Modified就不会改变。这是服务器返回304时的响应头浏览器收到304响应后,会从缓存中加载资源。如果协商缓存未命中,浏览器直接从服务器加载资源,则在重新加载时会更新Last-ModifiedHeader。下一个请求If-Modified-Since将启用上次返回的Last-Modified值Etag/If-None-Match。这两个值是服务器为每个资源生成的唯一标识字符串。只要资源改变,这个值就会改变;other判断过程类似于Last-Modified/If-Modified-Since。与Last-Modified不同的是,当服务器返回304NotModified响应时,由于已经重新生成了ETag,因此响应头将返回这个ETag,即使ThisETag与之前的没有变化。 4.既然Last-Modified和Etag  你可能会觉得用Last-Modified就可以让浏览器知道本地缓存副本是否足够新了,为什么还需要Etag呢?HTTP1.1中Etag的出现主要是为了解决几个比较难解决的Last-Modified问题:有些文件可能会周期性的改变,但是它的内容是不会改变的(只有改变的修改时间),这时候我们不要我不想让client认为文件被修改了,重新GET;有些文件修改非常频繁,比如秒内修改(比如1秒内修改N次),If-Modified-Since可以查得到的粒度是s级,这种修改无法判断(或者UNIX记录MTIME只能精确到秒);部分服务器无法准确获取文件的最后修改时间。这时候使用Etag可以更准确的控制缓存,因为Etag是服务器端自动生成或者开发者生成的相应资源在服务器端的唯一标识。Last-Modified和ETag可以一起使用。服务器会先验证ETag。如果一致,则继续比较Last-Modified,最后决定是否返回304。5.用户行为对缓存的影响网上偷一张图片基本可以描述用户行为对缓存的影响6.强缓存如何重新加载缓存资源上面说到,当使用强缓存时,浏览器不会向服务器发送请求,浏览器总是根据设置的缓存时间从缓存中获取资源。如果在此期间资源发生变化,浏览器将无法在缓存期间获取到最新的资源,那么如何防止这种情况发生呢?通过更新页面中引用的资源路径,让浏览器主动放弃缓存,加载新的资源。类似下图:这样每次文件变化都会产生一个新的查询值,这样查询值就不同了,也就是页面引用的资源路径不同,和之前缓存的资源被浏览器忽略,因为资源请求路径已经改变。