缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当 web 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。这样带来的好处有:缓解服务器端压力,提升性能(获取资源的耗时更短了)。对于网站来说,缓存是达到高性能的重要组成部分。缓存需要合理配置,因为并不是所有资源都是永久不变的:重要的是对一个资源的缓存应截止到其下一次发生改变(即不能缓存过期的资源)。
缓存的种类有很多,其大致可归为两类:私有与共享缓存。共享缓存存储的响应能够被多个用户使用。私有缓存只能用于单独用户。本文将主要介绍浏览器与代理缓存,除此之外还有网关缓存、CDN、反向代理缓存和负载均衡器等部署在服务器上的缓存方式,为站点和 web 应用提供更好的稳定性、性能和扩展性。--- 摘自《MDN - HTTP 缓存》
本文主要介绍浏览器缓存(即私有缓存)。在大多数场景下,缓存是最常见的优化手段,简单高效~
缓存的优势特点:
Client: 重复利用资源,减少网络开销,请求更快地响应解析,更好的用户体验
Network: 减少重复资源的网络开销,节省带宽,降低成本
Server: 减小服务器负载,避免过载造成性能瓶颈,简单高效的性能优化手段
2. 缓存机制
常见的 HTTP 缓存只能存储 GET 响应,对于其他类型的响应则无能为力。缓存的关键主要包括request method和目标URI(一般只有GET请求才会被缓存),流程图如下:
2.1 强缓存
强缓存:如果命中强缓存,浏览器发送的请求不会到达服务器,而是直接从浏览器缓存中读取数据,在chrome network中size显示为 disk cache 或者 memory cache,HTTP 状态码为200。
浏览器缓存策略
1. 前言
本文主要介绍浏览器缓存(即私有缓存)。在大多数场景下,缓存是最常见的优化手段,简单高效~
缓存的优势特点:
2. 缓存机制
常见的 HTTP 缓存只能存储
GET
响应,对于其他类型的响应则无能为力。缓存的关键主要包括request method和目标URI(一般只有GET请求才会被缓存),流程图如下:2.1 强缓存
强缓存:如果命中强缓存,浏览器发送的请求不会到达服务器,而是直接从浏览器缓存中读取数据,在chrome network中size显示为 disk cache 或者 memory cache,HTTP 状态码为200。
强缓存的字段:
Expires
(HTTP/1.0)、Cache-Control
(HTTP/1.0)、Pragma
(HTTP/1.0,效果同Cache-Control: no-cache,主要为了兼容,不做赘述)2.1.1 Expires
是一个绝对的时间,指定资源到期时间是服务器的具体时间点,该字段存在于服务器响应头, 即在此时间之前,直接读取浏览器缓存数据。如果值为 0, 代表着过去的日期,即该资源已经过期。
Expires
的优点:HTTP/1.0 的产物,向后兼容
绝对时间标示失效时间,方便对比
Expires
的缺点:2.1.2 Cache-Control
已知
Expires
的缺点之后,在HTTP/1.1中,新增了一个字段Cache-control
,该字段表示资源缓存的最大有效时间(相对时间),在该时间内,客户端不需要向服务器发送请求。Cache-control
常用值如下:Cache-Control
的优点:Cache-Control
的缺点:在HTTP/1.0中,无法使用
在缓存未过期之前,客户端是无法得知资源是否修改
2.2 协商缓存
当强缓存失效or没设置时,由客户端与服务器通过某种标识来判断(协商)资源是否可用,所以字段是成对出现的。请求头
If-Modified-Since
和响应头Last-Modified
配对,请求头If-None-Match
和响应头ETag
配对。如果命中,HTTP 状态码为304。2.2.1 Last-Modified和If-Modified-Since
是一个绝对的时间 ,表示服务器的资源最后一次修改的时间,在请求头中将上次的
Last-Modified
的值写入到请求头的If-Modified-Since
字段,对比该次请求响应头Last-Modified
与If-Modified-Since
时间,若时间一致,返回304状态码。Last-Modified
和If-Modified-Since
优点:HTTP/1.0 的产物,向后兼容
由于每次都经过服务器检验,不存在客户端无法得知资源是否修改的问题
Last-Modified
和If-Modified-Since
缺点:2.2.2 Etag和If-None-Match
为了解决
Last-Modified
和If-Modified-Since
的缺点 ,在HTTP/1.1 新增了Etag
和If-None-Match
字段,存储的是文件的特殊标识(一般由Hash生成),例如Nuxt.js
服务端渲染页面时自带Etag
。 同样在请求头中将上次的Etag
的值写入到请求头的If-None-Match
字段,对比该次请求响应头Etag
与If-None-Match
值,若一致,返回304状态码。Etag
和If-None-Match
优点:在HTTP/1.0中,无法使用
由于每次都经过服务器检验,不存在客户端无法得知资源是否修改的问题
可以更加精确的表示资源内容是否修改,可以识别1S内多次修改内容的情况
Etag
和If-None-Match
缺点:Etag
值会带来额外的性能损耗Etag
对比失效,无法起到协商缓存的作用3. 用户行为对浏览器缓存的影响
5. Vary
Vary
HTTP 响应头决定了对于后续的请求头,如何判断是请求一个新的资源还是使用缓存的文件。当缓存服务器收到一个请求,只有当前的请求和原始(缓存)的请求头跟缓存的响应头里的Vary都匹配,才能使用缓存的响应。简而言之,可以通过
Vary
字段来通知缓存哪些请求头字段用于区分相同的URL请求,服务端存在不同内容的响应。6. CDN(公有缓存)
在大多数前端项目中,静态资源都会使用CDN加速用户访问。
CDN
缓存策略因为服务商的不同而不同,但一般会根据源站响应头中的Cache-Control
和Expires
字段来设置节点缓存时间。因此,CDN缓存返回的Cache-Control
和Expires
一般源自服务器或者Nginx
配置。7. 总结
Cache-Control
高于Expires
,Etag
高于Last-modified
ETag
,没有必要再输出Last-Modified
,Etag
更能精准标识资源的修改情况Etag
不是自带的,有些框架会默认添加,例如 nuxt.js ,nodejs
可以使用 weak tag8. 参考