在学习强缓存与协商缓存之前,我们先聊聊什么是缓存?
缓存是指浏览器(客户端)在本地磁盘中对访问过的资源保存过的副本文件。
那么浏览器缓存有什么优点呢?
浏览器的请求流程:
浏览器在第一次请求后缓存资源,再次请求时:
1、浏览器获取该缓存资源的 header 中的信息,根据response header
中的expires
和cache-control
来判断是否命中强缓存,如果命中直接从缓存中读取资源。
2、如果没有命中强缓存,浏览器就会发送请求到服务器,这次请求会带上IF-Modified-Since
或者IF-None-Match
,它们的值分别是第一次请求返回Last-Modified
或者Etag
,由服务器来对比这一堆字段来判断是否命中。
3、如果命中,则服务器返回304状态码,并且不会返回资源内容,浏览器会从缓存中获取;否则服务器最终会返回资源的实际内容,并更新header中的相关缓存字段。
强缓存是根据返回头中的Expires
或者Cache-Control
两个字段控制的,都表示资源的缓存有效时间。如果二者同时存在,Cache-Control
的优先级高于Expires
。
Expires
:是http 1.0 的规范,值是一个GMT格式的时间点字符串,例如:Expires:Mon,18 Oct 2066 23:59:59 GMT。
这个时间点代表资源失效的时间,如果当前时间戳在这个失效时间之前,则判断命中缓存。
缺点: 由于失效时间是一个绝对时间,所以当服务器时间与客户端时间偏差较大时,就会导致缓存混乱。
Cache-Control
:是http 1.1的规范,一般使用该字段的max-age
值来进行判断。
优点: 这个值是一个相对时间,例如:Cache-Control:max-age=3600代表资源有效期为3600秒,并且返回头中的Date
表示消息发送的时间,表示当前资源在 Date ~ Date +3600s 这段时间里都是有效的。
关于Cache-Control
的其他值:
no-cache
:不使用本地内存,需要使用协商缓存。no-store
:禁止浏览器缓存数据,每次请求资源都会像服务器要完整的资源。public
:可以被所有用户缓存,包括终端用户和cdn等中间件代理服务器。private
:只能被终端用户的浏览器缓存。协商缓存由服务器决定缓存资源是否可用。
主要涉及到两对属性字段,都是成对出现的,即第一次请求的响应头带上某个字, Last-Modified
或者 Etag
,则后续请求则会带上对应的请求字段 If-Modified-Since
或者 If-None-Match
,若响应头没有 Last-Modified
或者 Etag
字段,则请求头也不会有对应的字段。
Last-Modified/If-Modified-Since
二者的值都是GMT格式的时间字符串。Last-Modified
标记最后文件修改时间,下一次请求时,请求头会带上If-Modified-Since
,用来告诉服务器本地缓存的文件最后修改的时间,服务器根据文件的最后修改时间判断资源是否有变化。若没有则返回 304 Not Modified
,请求不会返回资源内容,浏览器直接使用本地缓存。若有变化,就正常返回资源内容,新的 Last-Modified
会在 response header
返回,并在下次请求之前更新本地缓存的 Last-Modified
,下次请求时,If-Modified-Since
会启用更新后的 Last-Modified
。
Etag/If-None-Match
:只要资源有变化就这个值就会改变。服务器根据文件本身算出一个哈希值并通过 ETag
字段返回给浏览器,接收到 If-None-Match
字段以后,服务器通过比较两者是否一致来判定文件内容是否被改变。
与 Last-Modified
不一样的是,当服务器返回 304 Not Modified
的响应时,由于在服务器上ETag
重新计算过,response header
中还会把这个 ETag
返回,即使这个 ETag
跟之前的没有变化。
1、后端服务器,写入代码逻辑中:
res.setHeader('max-age': '3600 public')
res.setHeader(etag: '5c20abbd-e2e8')
res.setHeader('last-modified': Mon, 24 Dec 2018 09:49:49 GMT)
2、Nginx 配置:
add_header Cache-Control "max-age=3600"