注意:常见的 HTTP 缓存只能存储 GET 响应
通过复用以前获取的资源,可以显著提高网站和应用程序的性能
Web 缓存减少了请求的等待时间,并且节省了网络流量
缓存基本上可以分为两个大类
- 私有缓存(浏览器缓存)
- 共享缓存(代理缓存)
私有缓存
私有缓存是指只能给单个用户使用的缓存
比如通过浏览器打开过的页面会保存在浏览器这里,提供向后/向前导航,保存网页,查看源码等功能
共享缓存
共享缓存是指所有用户都可以访问的缓存。
我们常常用 nginx 做反向代理,这里我们假设目标服务器有一个图片是 1.jpg,且我们搭建了 redis缓存服务器
当一万个用户去请求这个图片,nginx 每次都得从目标服务器上拿 1.jpg 然后返给客户端
然而假设 1.jpg 是一万年都不会改变的,所以每次都去请求相同的资源对目标服务器造成了压力
所以当第一个请求该资源的时候,缓存服务器可以缓存下来 1.jpg
之后所有的该请求 nginx 都可以直接去缓存服务器这里拿到这个资源,大大减少了服务器的压力
Cache-control
缓存是有条件的,我们必须根据某个策略去控制如何缓存
Cache-Control 头表示如何处理该缓存,
请求头和响应头都支持这个属性。通过它提供的不同的值来定义缓存策略。
很多人把 no-store
和 no-cache
搞混,以为 no-cache
是没有缓存,它们是有区别的
-
没有缓存
Cache-Control: no-store
不得存储任何关于客户端请求和服务端响应的内容,每次请求都是最新资源
-
缓存但使用时需要验证(不是不缓存)
Cache-Control: no-cache
请求发出时,缓存服务器会将此请求发到服务器验证请求中所描述的缓存是否过期,若未过期,则缓存服务器才使用缓存(也就是我们常见的 304)
-
私有缓存
Cache-control: private
表示这些缓存专用于某个用户的,缓存服务器不能缓存此响应,也就是交给浏览器控制这些缓存
-
共享缓存
Cache-control: public
表示这些缓存可以被缓存服务器缓存,也就是设置了 public 你才能缓存上边说的 1.jpg
-
过期缓存
Cache-Control: max-age=100
表示资源能够被缓存的最大时间(秒),超过这个时间表示资源过期,注意该字段的优先级大于 Expires。如果设置了max-age,会忽略 Expires 头
-
自验证缓存
Cache-Control: must-revalidate
使用缓存资源时,必须先验证它的状态,已过期的缓存将不被使用
这里我把自己学习的时候的疑惑做一个解答
-
Cache-control: max-age=100 是如何工作的?
当客户端发送请求到缓存服务器的时候,先检查有无缓存
无缓存,缓存服务器会向目标服务器发送请求,假如得到响应 { Cache-contol: “max-age=100” }
缓存服务器会将该资源存储返回给客户端,响应头 { Cache-control: “max-age=100”, Age: 0 }
10s后,客户端再次发送请求到缓存服务器
缓存服务器检测到缓存后,返回资源并增加响应头 响应头 { Cache-control: “max-age=100”, Age: 10 }
100s 后,客户端再次发送请求到缓存服务器
缓存服务器检测缓存已经为过期缓存,那么会发送请求给目标服务器,并带有请求头,If-None-Match: …
若目标服务器返回 304,则缓存服务器会将资源返回给客户端,响应头 { Cache-control: ”max-age=100“, Age: 0 }
如果返回200,则将最新资源缓存,并返回给客户端
-
no-cache
和must-revalidate
有什么不同
no-cache
每次都会问服务器资源是否过期。请求头和响应头都可能会有
must-revalidate
判断过期时间,如果未过期直接返回资源,否则会重新请求。只用于响应头
Cache-control: no-cache
和Cache-control: max-age=0, must-revalidate
效果是一样的 -
Expires
和Cache-control: max-age=100
有什么不同
Expires
优先级低于max-age
,Expires 表示过期的日期,表示某个绝对时间(年/月/日 时:分:秒)过期
max-age
优先级高于Expires
,表示过期时间(秒),表示某个时间(100s)后过期 -
缓存头的优先级
Cache: max-age=x
>Expires
>Last-Modified
-
缓存服务器通过什么去请求服务器判断缓存是否过期
当资源是过期的时候,缓存服务器会将请求加上If-None-Match
字段发送到目标服务器,如果服务器返回 304,则缓存服务器更新缓存资源信息,并返回该资源。
If-None-Match
的值为响应头的Etag
,Etag
是根据资源生成的一串标识符,如果资源未更改,他就不会改变 -
Last-Modified 如何计算缓存的过期时间
响应头里的 Date 的值减去 Last-Modified 的值除以10,对于为什么除以 10,这是协议里规定的,我也不知道 -
缓存失效日期时间计算公式
expirationTime = responseTime + freshnessLifetime - currentAge
responseTime
表示接收到此响应的那个时间点
freshnessLifetime
表示 max-age 的值,或者是 Data - Expires 的值,或者是 上边 Last-Modified 的过期时间
currentAge
表示此响应的那个时间点过去的秒数,也就是响应头里的 Age
总结一下我理解的 强缓存 和 协商缓存。强缓存和协商缓存是有无 no-cache 的区别,一个是直接命中本地缓存,一个是需要和服务器验证是否可以使用缓存
我的能力有限,所以如果有什么不对的地方,请大家指出