浏览器缓存

强缓存和协商缓存

Posted by Lan on July 29, 2019

强缓存和协商缓存

#缓存

客户端(浏览器)会将从服务端取得的资源进行缓存,以便在不必要的情况下减少对服务端的请求,同时也给客户端更快更好的用户体验。

#请求资源示意图

第一次请求资源

第一次请求资源

后续的请求

后续请求资源

缓存过程

  • 浏览器在再次获取资源时,先获取缓存资源中的header信息,依据Expire/Cache-control,判断是否直接取得强缓存,若符合条件,则直接取得本地缓存,不与服务器有任何通信过程。

  • 如果在上一步,并没有是直接取得强缓存,客户端会发送请求到服务端,服务端会在响应header中携带Last-Modified/If-Modified-Since和Etag/If-None-Match信息,依据这两对信息的比对结果,来判断是否是协商缓存,若是,服务器会返回新的响应,响应中带有更新的header信息,但不返回新的数据资源,此时返回状态码304,这就告知客户端直接从缓存资源中取数据;若经过header中信息的比对结果并不是协商缓存,则服务器直接返回新的资源

强缓存和协商缓存

强缓存

  • 强缓存其实就是依据header中的Expire/Cache-control去判断是否直接去获取本地缓存,而不用与服务器进行沟通。
  • header字段
    1. Expire

    值是一个GMT时间,通过比对当前的请求时间和Expire的值,如果请求时间在此值之前,则使用本地缓存,否则就会向服务器请求 2. cache-control :max-age=number

    max-age是相对于第一次请求时间的相对值,这个值就是第一次请求时间和资源的过期时间cache-control计算得来的,(理解为:第一次请求时间+缓存有效时间),通过当前的请求时间与这个值进行比较,以判断是否强缓存有效

    • cache-control的几个值:

    • no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。

    • no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。

    • public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。

    • private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存

同时存在时的优先级:cache-control高于Expire

协商缓存

  • 协商缓存简单而言就是服务器与客户端进行协商,看是否还可以用客户端缓存或者服务端返回新的资源。
  • 流程 发请求–>看资源是否过期–>过期–>请求服务器–>服务器对比资源是否真的过期–>没过期–>返回304状态码–>客户端用缓存的老资源。 请求资源时,把用户本地该资源的 etag 同时带到服务端,服务端和最新资源做对比。 如果资源没更改,返回304,浏览器读取本地缓存。 如果资源有更改,返回200,返回最新的资源。
  • header字段
    1. Last-Modified/If-Modified-Since

      二者的值都是GMT格式的时间字符串,具体过程: 浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在respone的header加上Last-Modified的header,这个header表示这个资源在服务器上的最后修改时间

      浏览器再次跟服务器请求这个资源时,在request的header上加上If-Modified-Since的header,这个header的值就是上一次请求时返回的Last-Modified的值

      服务器再次收到资源请求时,根据浏览器传过来If-Modified-Since和资源在服务器上的最后修改时间判断资源是否有变化,如果没有变化则返回304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容。当服务器返回304 Not Modified的响应时,response header中不会再添加Last-Modified的header,因为既然资源没有变化,那么Last-Modified也就不会改变,这是服务器返回304时的response header

      浏览器收到304的响应后,就会从缓存中加载资源

      如果协商缓存没有命中,浏览器直接从服务器加载资源时,Last-Modified的Header在重新加载的时候会被更新,下次请求时,If-Modified-Since会启用上次返回的Last-Modified值

  1. Etag/If-None-Match

    这两个值是由服务器生成的每个资源的唯一标识字符串,只要资源有变化就这个值就会改变;其判断过程与Last-Modified/If-Modified-Since类似,与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化。

    Etag存在的意义,相对于Last-Modified

  • 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;

  • 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);

  • 某些服务器不能精确的得到文件的最后修改时间。

##优先级:Etag高

为什么要有etag? 你可能会觉得使用last-modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要etag呢?HTTP1.1中etag的出现(也就是说,etag是新增的,为了解决之前只有If-Modified的缺点)主要是为了解决几个last-modified比较难解决的问题:

一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新get;

某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),if-modified-since能检查到的粒度是秒级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);

某些服务器不能精确的得到文件的最后修改时间。