什么是 HTTP 缓存
缓存是一种保存资源副本并在下次请求时直接使用该副本的技术
缓存的基础是建立在两者文件路径完全相同的情况下
http缓存主要针如css,js,图片等更新频率不大的静态文件
缓存技术的优点
- 减少重复数据请求,避免通过网络再次加载资源,节省流量
- 降低服务器压力,提升网站性能
- 加快客户端加载网页的速度,提升用户体验
缓存类型
强缓存
不需要发送请求到服务端,直接读取浏览器本地缓存
由响应头中的
Cache-Control
或者Expires
字段控制,表示资源的缓存有效时间
-
Expires
是 http 1.0 的规范,值是一个GMT
格式的时间点字符串(expires: Thu, 17 Mar 2022 07:19:55 GMT
)。这个时间点代表资源失效时间,如果之后的请求时间戳在这个时间戳之前,则命中强缓存。如果服务器时间和客户端时间偏差较大时,会导致缓存混乱。 -
Cache-Control
是 http1.1 的规范,使用max-age
来设置资源可以被缓存多长时间,值是一个相对时间,相对于用户请求时间,单位为秒。用户请求时间 +max-age
即为强缓存有效时间,在有效时间内重复请求,会命中强缓存。Cache-Control
可设置的其他值:no-cache
: 浏览器缓存了数据,但是再次请求时,是不直接使用强缓存,强制使用协商缓存,即每次请求都必须向服务器发送no-store
: 直接禁止浏览器缓存数据,每次请求资源都会向服务器获取完整的资源public
: 可以被所有用户缓存,包括终端用户和cdn
等中间件代理服务器private
: 只能被终端用户的浏览器缓存s-maxage
: 和max-age
一样,不过它只针对代理服务器而言
-
强缓存优先级
max-age
比 Expires
优先级高,并存时,采用 max-age
值
协商缓存(对比缓存)
最终由服务器决定是否使用缓存,即客户端获取资源时,会向服务器发送请求,用服务器判断是否使用缓存数据。
协商缓存下如果命中缓存,服务器端响应的状态码为304(not modified)。
两组规则:
Last-Modified / If-Modified-Since
和ETag / If-None-Match
-
Last-Modified / If-Modified-Since
1、服务器响应浏览器的响应时,会在响应头里添加一个字段
Last-Modified
,值为资源的最后修改时间2、浏览器之后再请求时,会在请求头添加字段
If-Modified-Since
, 值为服务器上一次响应的Last-Modified
值3、服务器会对比源资源最后修改时间和web请求头里的
If-Modified-Since
字段值。如果大于If-Modified-Since
,这说明资源有更新,缓存已失效,浏览器则不能再使用之前的缓存副本,返回完整的资源数据并响应码为200
;如果相等,则表明资源未失效,响应头信息中状态码为304
,响应消息体中没有数据 -
ETag / If-None-Match
1、服务器响应浏览器的响应时,会在响应头里添加一个字段
ETag
,值为资源的一个唯一标识(生成规则实现方式不一,由具体的服务器决定)2、浏览器之后再请求时,会在请求头添加
If-None-Match
,值为服务器上一次响应的ETag
值3、服务器比对源资源的
ETag
是否和 web 请求头的If-None-Match
字段值一致。不一致则说明文件有更新,本地缓存已失效,响应完整的资源数据并响应码为200
;如果一致,则命中协商缓存,响应码为304
- 协商缓存两组规则的优先级
当
Last-Modified / If-Modified-Since
和ETag / If-None-Match
并存时,使用ETag / If-None-Match
HTTP 缓存的流程图
Q & A
1、既然已经存在 Last-Modified / If-Modified-Since
,为什么规范里由引入了 ETag / If-None-Match
?
ETag
值都是由服务器为每一个资源生成的唯一标识串,只要资源有变化就这个值就会改变。
HTTP1.1
用 ETag
来判断请求的文件是否被修改,主要为了解决 Last-Modified
无法解决的一些问题:
1、一些文件也许会做周期性的更改,但是他的内容并不更改(仅仅改变的修改时间),这个时候并不希望客户端认为这个文件被修改了重新GET
2、某些文件修改非常频繁,1秒内修改了N次,If-Modified-Since
能检查到的粒度是秒级的,这种判断无法修改
3、某些服务器不能精确的得到文件的最后修改时间
为此,HTTP1.1
引入了 ETag
。但标准并没有规定ETag的内容是什么或者说要怎么实现,唯一规定的是`ETag 需要放在双引号内。
max-age
和 Expires
的区别
1、max-age
是 http 1.1
的属性, Expires
是 http 1.0
的属性,为了做到向下兼容,一般写两个。但在 http 1.1
的环境下, max-age
比 Expires
优先级高
2、max-age
是相对过期时间, Expires
是绝对过期时间。 max-age
在浏览器成功缓存文件后,只需相对成功之后的多长时间不再发起请求就好了,而 Expires
总是需要服务器返回一个精准的 GMT
格式的日期,并以这个日期为标准来判断缓存是否过期。本地时间和服务器时间有较大偏差时,缓存就会不准确
单页面缓存应用实践
-
html
文件:应用唯一入口,也是加载资源的唯一入口,所以建议html
文件禁止使用缓存Cache-Control: no-store
,保证用户请求到的html
文件永远为最新的 -
JS、CSS
文件:项目基本使用webpack
等构建工具,资源名称由 HASH值 进行标识,资源更新时,则 HASH值 会发生改变,文件路径改变,故不再满足缓存条件,首次加载时必然请求服务器。所以缓存策略可以将max-age
配置一个绝对大的值 -
image、media
等媒体资源:根据网站实际情况做缓存策略
provisional headers are shown (显示临时报头)
上图表示:真正的请求并没有被发送,出现此种情况的原因是真正的Header只有在服务器端响应的时候更新。显示临时报文的几种情况:
1、命中强缓存,请求未发出
2、跨域,请求被浏览器拦截
3、请求被浏览器插件拦截
4、服务器出错或者超时,服务器端没有响应