虽然 HTTP 缓存不是必须的,但重用缓存的资源通常是必要的。然而常见的 HTTP 缓存只能存储 GET 响应,对于其他类型的响应则无能为力。缓存的关键主要包括request method和目标URI(一般只有GET请求才会被缓存)。
http1.0时期的缓存方案
Pragma | 控制缓存行为,如果设置为no-cache,表示禁用缓存。和http1.1中的Cache-Control头部功能相似 | |
---|---|---|
Expires | 过期时间,用的是服务器的时间,如果客户端和服务器时间不一致,则会存在缓存时间误差。http1.1可以用Cache-Control来实现相似的功能。 |
如果使用了Pragma: ‘no-cache’的话,再设置Expires或者Cache-Control,就没有用了,说明Pragma的权值比后两者高。
如果设置了Expires之后,客户端在需要请求数据的时候,首先会对比当前系统时间和这个Expires时间,如果没有过那个时间,则直接读取本地磁盘中的缓存数据,不发送请求。
http1.1的缓存方案
Cache-control
**cache-control作为请求头部 | |
---|---|
指令 | 说明 |
no-cache | 强制向源服务器再次验证 |
no-store | 不缓存请求或相应的任何内容 |
max-age=[秒] | 相应的最大Age值 |
max-stale=(=[秒]) | max-stale=(=[秒]) |
min-fresh=[秒] | 期望在指定时间内的响应仍有效 |
no-transform | 代理不可更改媒体类型 |
only-if-cached | 从缓存获取资源 |
cache-extension | 新指令标记(token) |
cache-control作为响应头部 | |
---|---|
指令 | 说明 |
public | 可向任意方提供响应的缓存 |
private | 仅向特定用户返回响应 |
no-cache | 缓存前必需先确认其有效性 |
no-store | 不缓存请求或相应的任何内容 |
no-transform | 代理不可更改媒体类型 |
must-revalidate | 可缓存但必须再向源服务器进行确认 |
max-age=[秒] | 响应的最大Age值 |
s-maxage=[秒] | 公共缓存服务器响应的最大Age值 |
cache-extension | 新指令标记(token) |
“no-cache”和“no-store”
“no-cache”表示必须先与服务器确认返回的响应是否发生了变化,然后才能使用该响应来满足后续对同一网址的请求。 因此,如果存在合适的验证令牌 (ETag),no-cache 会发起往返通信来验证缓存的响应,但如果资源未发生变化,则可避免下载。
相比之下,“no-store”则要简单得多。 它直接禁止浏览器以及所有中间缓存存储任何版本的返回响应,例如,包含个人隐私数据或银行业务数据的响应。 每次用户请求该资产时,都会向服务器发送请求,并下载完整的响应。
“public”和“private”
如果响应被标记为“public”,则即使它有关联的 HTTP 身份验证,甚至响应状态代码通常无法缓存,也可以缓存响应。 大多数情况下,“public”不是必需的,因为明确的缓存信息(例如“max-age”)已表示响应是可以缓存的。
相比之下,浏览器可以缓存“private”响应。 不过,这些响应通常只为单个用户缓存,因此不允许任何中间缓存对其进行缓存。 例如,用户的浏览器可以缓存包含用户私人信息的 HTML 网页,但 CDN 却不能缓存。
“max-age”
指令指定从请求的时间开始,允许提取的响应被重用的最长时间(单位:秒)。 例如,“max-age=60”表示可在接下来的 60 秒缓存和重用响应。
应用 HTTP/1.1 版本的缓存服务器遇到同时存在 Expires 首部字段的情 况时,会优先处理 max-age 指令,而忽略掉 Expires 首部字段。而 HTTP/1.0 版本的缓存服务器的情况却相反,max-age 指令会被忽略。
Cache-Control: s-maxage=604800(单位 :秒)
s-maxage 指令的功能和 max-age 指令的相同,它们的不同点是 smaxage 指令只适用于供多位用户使用的公共缓存服务器 ,如CDN缓存。也就是 说,对于向同一用户重复返回响应的服务器来说,这个指令没有任何 作用。
另外,当使用 s-maxage 指令后,则直接忽略对 Expires 首部字段及 max-age 指令的处理。
定义最佳cache-control策略
ETag
首部字段 ETag 能告知客户端实体标识。它是一种可将资源以字符串 形式做唯一性标识的方式。服务器会为每份资源分配对应的 ETag 值。
强 ETag 值和弱 Tag 值
W/ 可选’W/‘(大小写敏感) 表示使用弱验证器。
弱验证器很容易生成,但不利于比较。
强验证器是比较的理想选择,但很难有效地生成。 相同资源的两个弱Etag值可能语义等同,但不是每个字节都相同。
“
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
ETag: W/"0815"
缓存分类
强缓存
强制缓存在缓存数据未失效的情况下(即Cache-Control的max-age没有过期或者Expires的缓存时间没有过期),那么就会直接使用浏览器的缓存数据,不会再向服务器发送任何请求。强制缓存生效时,http状态码为200。这种方式页面的加载速度是最快的,性能也是很好的,但是在这期间,如果服务器端的资源修改了,页面上是拿不到的,因为它不会再向服务器发请求了。这种情况就是我们在开发种经常遇到的,比如你修改了页面上的某个样式,在页面上刷新了但没有生效,因为走的是强缓存,所以Ctrl + F5一顿操作之后就好了。 跟强制缓存相关的header头属性有(Pragma/Cache-Control/Expires)
在chrome浏览器中返回的200状态会有两种情况:
1、from memory cache
(从内存中获取/一般缓存更新频率较高的js、图片、字体等资源)
2、from disk cache
(从磁盘中获取/一般缓存更新频率较低的js、css等资源)
这两种情况是chrome自身的一种缓存策略,这也是为什么chrome浏览器响应的快的原因。其他浏览返回的是已缓存状态,没有标识是从哪获取的缓存。
协商缓存
当第一次请求时服务器返回的响应头中没有Cache-Control和Expires或者Cache-Control和Expires过期还或者它的属性设置为no-cache时(即不走强缓存),那么浏览器第二次请求时就会与服务器进行协商,与服务器端对比判断资源是否进行了修改更新。如果服务器端的资源没有修改,那么就会返回304状态码,告诉浏览器可以使用缓存中的数据,这样就减少了服务器的数据传输压力。如果数据有更新就会返回200状态码,服务器就会返回更新后的资源并且将缓存信息一起返回。跟协商缓存相关的header头属性有(ETag/If-None-Match 、Last-Modified/If-Modified-Since)请求头和响应头需要成对出现
注意:
ETag/If-None-Match是在HTTP/1.1出现的,主要是解决以下问题:
(1)、Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
(2)、如果某些文件被修改了,但是内容并没有任何变化,而Last-Modified却改变了,导致文件没法使用缓存
(3)、有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形
缓存流程图
参考
https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching
https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ
https://segmentfault.com/a/1190000006689795
一文读懂http缓存(超详细)
HTTP缓存技术详解
MDN-ETag
说明:此文仅用于知识整理及学习,若有侵权请联系我删除。