浏览器_缓存机制 - zen0822/interview GitHub Wiki
缓存机制
大致请求过程描述
-
浏览器第一次加载资源,服务器返回 200,浏览器将资源文件从服务器上请求下载下来,并把
response header
及该请求的返回时间一并缓存; -
下一次加载资源时,先比较当前时间和上一次返回 200 时的时间差,如果没有超过
cache-control
(HTTP1.1)设置的max-age
,则没有过期,命中强缓存请求获得 200,不发请求直接从本地缓存读取该文件(如果浏览器不支持 HTTP1.1,则用expires
判断是否过期);如果时间过期,则向服务器发送header
带有If-None-Match
和If-Modified-Since
的请求 -
服务器收到请求后,优先根据
Etag
的值判断被请求的文件有没有做修改,Etag
值一致则没有修改,命中协商缓存,返回304
;如果不一致则有改动,直接返回新的资源文件带上新的Etag
值并返回200
; -
如果服务器收到的请求没有
Etag
值,则将If-Modified-Since
和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回304
;不一致则返回新的last-modified
和文件并返回200
;
强缓存
HTTP1.0
判断缓存过期时间是由 response header
的 expires
决定的,并且是一个标准的日期时间(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 秒,都能正确使用缓存
Expires
和Cache-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格式的时间字符串,具体过程:
-
浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在
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
值
Etag
web
服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。
If-None-Match
当资源过期时(使用 Cache-Control
标识的 max-age
),发现资源具有 Etage
声明,则再次向 web
服务器请求时带上头 If-None-Match
(Etag
的值)。web
服务器收到请求后发现有头 If-None-Match
则与被请求资源的相应校验串进行比对,决定是否命中协商缓存;
面试回答
- 简要说说 http 请求的缓存
浏览器缓存分为两种,一种是强缓存,一种是协商缓存。强缓存就是在规定的时间内,不询问服务器强制使用浏览器缓存,时间的设置是根据响应头的
expires
字段和cache-control
字段,expires
的值是一个绝对时间,在这个时间之前,浏览器都会使用强缓存,这个方法的缺点就是如果客户端和服务端时间不同步,会出现是用不了缓存的情况,cache-control
这个字段是http1.1
出的,它的值是一个相对时间,在这个相对时间之内都是用强缓存,这个弥补了expires
的缺点,不管客户端时间正不正确,都能在有效时间内使用强缓存。另外一种就是协商缓存,浏览器会带着if-Modified-Since
字段询问服务器是否使用缓存,服务器根据传来的if-Modified-Since
时间来判断是否需要使用缓存。
- 如果 http 响应头中 ETag 值改变了,是否意味着文件内容一定已经更改
不一定,由服务器中 ETag 的生成算法决定。 比如 nginx 中的 etag 由 last_modified 与 content_length 组成,而 last_modified 又由 mtime 组成 当编辑文件却未更改文件内容时,mtime 也会改变,此时 etag 改变,但是文件内容没有更改。