浏览器_缓存机制 - zen0822/interview GitHub Wiki

缓存机制

大致请求过程描述

图片:图解缓存机制

  1. 浏览器第一次加载资源,服务器返回 200,浏览器将资源文件从服务器上请求下载下来,并把 response header 及该请求的返回时间一并缓存;

  2. 下一次加载资源时,先比较当前时间和上一次返回 200 时的时间差,如果没有超过 cache-control(HTTP1.1)设置的 max-age,则没有过期,命中强缓存请求获得 200,不发请求直接从本地缓存读取该文件(如果浏览器不支持 HTTP1.1,则用 expires 判断是否过期);如果时间过期,则向服务器发送 header 带有 If-None-MatchIf-Modified-Since 的请求

  3. 服务器收到请求后,优先根据 Etag 的值判断被请求的文件有没有做修改,Etag 值一致则没有修改,命中协商缓存,返回 304;如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200

  4. 如果服务器收到的请求没有 Etag 值,则将 If-Modified-Since 和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回 304;不一致则返回新的 last-modified 和文件并返回 200

强缓存

HTTP1.0 判断缓存过期时间是由 response headerexpires 决定的,并且是一个标准的日期时间(ex:Thu May 09 2019 15:39:19 GMT+0800),由于客户端的时间不一定和服务端的时间一致,会有歧义。所以 HTTP1.1 新增了 cache-control 设置的 max-age(ex:Cache-Control: private, max-age=3600, no-cache),这个是由服务端确定的间隔多长缓存失效的参数。

Expires: Thu, 18 Oct 2018 13:28:45 GMT (http1.0) 意思是这个时间之前强制使用浏览器缓存,缺点是这个时间是绝对时间,所以客户端时间不正确会导致客户端和服务端时间不同步的情况出现。

Cache-Control: max-age=3600 (http1.1) 意思是客户端相对当时客户端 3600 秒之内强制使用浏览器缓存,优点是不管客户端时间如何,只要没超过 3600 秒,都能正确使用缓存

ExpiresCache-Control 都存在时以 Cache-Control 为准

Cache-Control

在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存,主要取值为:

  • public:所有内容都将被缓存(客户端和代理服务器都可缓存)
  • private:所有内容只有客户端可以缓存,Cache-Control的默认取值
  • no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
  • no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
  • max-age=xxx (xxx is second):缓存内容将在xxx秒后失效

协商缓存

Last-Modified/If-Modified-Since

二者的值都是GMT格式的时间字符串,具体过程:

  1. 浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在 responeheader 加上 Last-Modifiedheader,这个 header 表示这个资源在服务器上的最后修改时间

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

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

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

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

Etag

web 服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。

If-None-Match

当资源过期时(使用 Cache-Control 标识的 max-age),发现资源具有 Etage 声明,则再次向 web 服务器请求时带上头 If-None-MatchEtag 的值)。web 服务器收到请求后发现有头 If-None-Match 则与被请求资源的相应校验串进行比对,决定是否命中协商缓存;

面试回答

  1. 简要说说 http 请求的缓存

浏览器缓存分为两种,一种是强缓存,一种是协商缓存。强缓存就是在规定的时间内,不询问服务器强制使用浏览器缓存,时间的设置是根据响应头的 expires 字段和 cache-control 字段,expires 的值是一个绝对时间,在这个时间之前,浏览器都会使用强缓存,这个方法的缺点就是如果客户端和服务端时间不同步,会出现是用不了缓存的情况,cache-control 这个字段是 http1.1 出的,它的值是一个相对时间,在这个相对时间之内都是用强缓存,这个弥补了 expires 的缺点,不管客户端时间正不正确,都能在有效时间内使用强缓存。另外一种就是协商缓存,浏览器会带着 if-Modified-Since 字段询问服务器是否使用缓存,服务器根据传来的 if-Modified-Since 时间来判断是否需要使用缓存。

  1. 如果 http 响应头中 ETag 值改变了,是否意味着文件内容一定已经更改

不一定,由服务器中 ETag 的生成算法决定。 比如 nginx 中的 etag 由 last_modified 与 content_length 组成,而 last_modified 又由 mtime 组成 当编辑文件却未更改文件内容时,mtime 也会改变,此时 etag 改变,但是文件内容没有更改。

参考

带你10分钟了解http的cache设置