浏览器的缓存规则是在 http 协议头和 html 页面的 meta 标签中定义的。主要分为两部分:强缓存和协商缓存。
强缓存是指缓存的副本在有效期内,浏览器直接获取这个副本并渲染。
强缓存主要涉及的 http 协议报头有:Expires,cache-control。
强缓存的过程:浏览器发起 http 请求,浏览器缓存中查找该请求的结果以及缓存标识,缓存副本在有效期内,该请求返回状态码 200,从 disk cache 或 memory cache (size 中显示 from disk cache 或 from memory cache)中返回。如果缓存副本并不在有效期内,浏览器将发起 http 请求到服务端,服务端返回请求结果和缓存规则,并将请求结果和缓存标识存在浏览器缓存中。
Expires:是HTTP/1的产物,是一个绝对的时间,如果浏览器时间还没有超过这个expires时间,代表缓存还有效。直接从缓存中读取资源。
cache-control:是HTTP/1.1提出的。
指令 | 作用 |
public |
表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等 等)缓存。 |
private |
表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能 缓存它),可以缓存响应内容。 |
no-cache | 在释放缓存副本之前,强制高速缓存将请求提交给原始服务器进行验证。 |
only-if-cached |
表明客户端只接受已缓存的响应,并且不要向原始服务器检查是否有更 新的拷贝 |
max-age=<seconds> |
设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。 与Expires相反,时间是相对于请求的时间。 |
s-maxage=<seconds> |
覆盖max-age 或者 Expires 头,但是仅适用于共享缓存(比如各个代理), 并且私有缓存中它被忽略。 |
max-stale[=<seconds>] |
表明客户端愿意接收一个已经过期的资源。 可选的设置一个时间(单位秒), 表示响应不能超过的过时时间。 |
min-fresh=<seconds> | 表示客户端希望在指定的时间内获取最新的响应。 |
如果 cache-control 和 expires 同时存在的话,cache-control 优先级高于 Expires。Expires 设置的过期时间受客户端本地时间影响。
协商缓存是在强缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。
协商缓存的过程:浏览器发起 http 请求,浏览器缓存返回缓存标识(请求的缓存结果失效),浏览器携带该资源的缓存标识,向服务器发起 http 请求,如果服务器返回 304 和 not modified,浏览器向浏览器缓存获取该请求的缓存结果,浏览器环迅返回该请求结果。如果服务器返回 200 和请求结果(该资源更新了,重新返回请求结果),浏览器将该请求结果和缓存标识存入浏览器缓存中。
协商缓存主要涉及的 http 协议报头有:Last-Modified 和 ETag。
Last-Modified:浏览器在第一次访问资源时,服务器返回响应头Last-Modified,值是这个资源在服务器上的最后修改时间,浏览器接收后缓存文件和header;再次请求资源,浏览器检测有 Last-Modified 就会添加请求头 If-Modified-Since,值是Last-Modified 的值。服务器接收请求会根据 If-Modified-Since 中的值与服务器中这个资源的最后修改时间对比,如果没有变化返回 304 和空的响应体,直接从缓存读取。如果 If-Modified-Since 时间小于服务器中这个资源的最后修改时间,说明文件有更新,于是返回新的资源文件和 200。
Etag 和 If-None-Match:Etag返回的是资源文件的唯一标识,只要文件有变化吗Etag就会重新生成。浏览器在下次加载资源时带上 If-None-Match,值是ETag。服务器比较跟资源文件的ETag是否一致。如果一致,则直接返回 304 。
如果 ETag 和 Last-Modified 同时存在,ETag 优于 Last-Modified.Last-Modified
的时间单位是秒,秒级别的修改,不能保证精度。如果是负载均衡的服务器各个服务器生成的 Last-Modified 也有可能不一致。在性能上,ETag 要逊于 Last-Modified,ETag
需要服务器通过算法计算一个hash值。
协商缓存是无法减少请求数的开销的,但是可以减少返回的正文大小。一般来说,对于勤改动的html文件,使用协商缓存是一种不错的选择。
F5 刷新,Expires/cache-control 无效了,Last-Modified/ETag 还是有效的。
Ctrl + F5 强制刷新,Expires/cache-control,Last-Modified 都无效。
不被缓存的请求:
- 包含cache-control:no-cache,pragma:no-cache 或者 cache-control:max-age=0等。
- 需要根据cookie,认证信息等决定输入内容的动态请求是不能被缓存的。
- post 请求。
基于缓存策略:
- 同一个url保证稳定性。
- 给 css 、js 、图片等资源增加 HTTP 缓存头(对于不常修改的静态资源,设置一个较长的时间),入口 html 不建议设置缓存。
- 减少对 cookie 的依赖,每次 get 和 post 请求,都带上 cookie 增加网络传输流量,导致增长交互时间,同时cache 是很难缓存的。
参考博客:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers
https://www.jianshu.com/p/54cc04190252
http://www.alloyteam.com/2012/03/web-cache-2-browser-cache/