# HTTP缓存

Web缓存通过复用以前获取的资源,减少等待时间和网络流量,减少了显示资源表示形式所需的时间,可以显著提高网站和应用程序的性能。通过使用HTTP缓存,可以使网站的响应更加敏捷。

但是,缓存也需要合理配置,因为并不是所有资源都是永久不变的。重要的是,对一个资源的缓存应截止到其下一次发生改变(即不能缓存过期的资源)。

缓存可分为私有与共享缓存两类:

  • 共享缓存存储的响应能够被多个用户使用,例如网关缓存、CDN、反向代理缓存和负载均衡器等。
  • 私有缓存只能用于单个用户,例如浏览器缓存(Brower Caching)。

HTTP缓存只应该缓存GET请求,因为其是幂等的。

# 缓存规则

按照缓存规则,缓存可以分为强制缓存协商缓存两类:

强制缓存是指当缓存数据库中已有所请求的数据时,直接从缓存数据库中获取数据。只有缓存数据库中没有所请求的数据时,才会从服务端获取数据。

协商缓存又称对比缓存,客户端会先从缓存数据库中获取到一个缓存数据的标识,然后请求服务端验证是否失效(新鲜),如果没有失效服务端会返回304,此时客户端直接从缓存中获取所请求的数据,如果标识失效,服务端会返回更新后的数据。

两类缓存机制可以同时存在,强制缓存的优先级高于协商缓存,当执行强制缓存时,如若缓存命中,则直接使用缓存数据库数据,不在进行缓存协商。

# 缓存控制

缓存相关的规则信息包含在header中,具体如下:

# 强制缓存

对于强制缓存,服务器响应的header中可以用以下两种方式表明过期时间:

Expires:服务端返回的数据到期时间。当再次请求时的请求时间小于返回的此时间,则直接使用缓存数据。Expires属于HTTP 1.0协议,但由于服务端时间和客户端时间可能有误差,会导致缓存命中的误差,现在大多数使用Cache-Control替代。

Cache-ControlCache-Control有很多属性,不同的属性代表的意义也不同。max-age=t可用来指定时间,表示t秒之后缓存内容将失效。

当在Cache-Control中设置了max-age时,Expires将会被忽略。

# 协商缓存

协商缓存需要进行对比判断是否可以使用缓存。

Last-Modified

浏览器第一次请求数据时,服务器会将最后修改时间以Last-Modified: <date>响应首部的形与数据一起发送给客户端。

当需要对缓存进行在验证时,浏览器会将该最后修改时间放到If-Modified-Since请求首部中,发送给服务器。服务器会将此时间与服务器上请求资源的最后修改时间进行对比,如果一致则返回一个304 Not Modified响应。304的响应头也可以同时更新缓存文档的过期时间。否则返回带有新数据的状态为200的响应。

另外还有一个If-Unmodified-Since请求首部,意思为,当数据没有被修改时,返回数据。否则返回一个412 Precondition failed的响应。

对于Last-Modified而言,如果一个资源被修改的,但是实际内容根本没发生改变,会因为Last-Modified时间匹配不上而返回了整个实体给客户端。因此,Last-Modified又被称为弱校验

ETag

为了解决Last-Modified问题,HTTP 1.1推出了被称为实体标签ETag强校验。

ETag是附加到文档上的任意标签(引用字符串),可能包含了文档的序列号或者版本名,或者是文档内容的校验及其他指纹信息。

Last-Modified类似,服务器响应请求时,通过此字段告诉浏览器当前资源在服务器生成的唯一标识(生成规则由服务器决定)。

再次请求服务器时,浏览器会将ETag的值放到If-None-Match请求首部中。服务器会将此值与被请求资源的唯一标识进行对比。相同返回304 Not Modified,不同返回带有新的资源内容的200的响应。

ETag的缺点就是其值是使用算法得出的,会占用服务端计算的资源。

# Cache-Control

HTTP/1.1定义了Cache-Control请求首部来区分不同的缓存策略,请求首部和响应首部都支持。

  • Cache-Control: no-store,禁止缓存。缓存中不会存储任何关于客户端请求和服务端响应的内容
  • Cache-Control: no-cache,缓存但重新验证。每次有请求发出时,缓存会将此请求发到服务器,以验证请求中所描述的缓存是否过期,若未过期才使用本地缓存副本。
  • Cache-Control: public公共缓存或Cache-Control: private私有缓存。公共缓存可以被任何中间人(比如中间代理、CDN等)缓存。私有缓存表示该响应是专用于某单个用户的,中间人不能缓存此响应,只能应用于浏览器私有缓存中。
  • Cache-Control: max-age=<seconds>。表示资源能够被缓存(保持新鲜)的最大时间
  • Cache-Control: must-revalidate。在事先没有跟原始服务器再验证的情况下,不能提供这个对象的陈旧副本,但缓存可以提供新鲜副本。如果在进行must-revalidate新鲜度检查时,原始服务器不可用时要返回504 Gateway Timeout错误

# 不同刷新的请求执行过程

  • 浏览器地址栏中写入URL,回车浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿。(最快)
  • F5,就是告诉浏览器,别偷懒,好歹去服务器看看这个文件是否有过期了。于是浏览器就胆胆襟襟的发送一个请求带上If-Modify-Since
  • Ctrl+F5告诉浏览器,你先把你缓存中的这个文件给我删了,然后再去服务器请求个完整的资源文件下来。于是客户端就完成了强行更新的操作.

参考资料:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ

https://juejin.cn/post/6844903517702848526#heading-1