HTTP 缓存
HTTP 缓存会存储与请求关联的响应,并将存储的响应复用于后续请求.
可复用性有几个优点。 首先,由于不需要将请求传递到源服务器,因此客户端和缓存越近,响应速度就越快。 最典型的例子是浏览器本身为浏览器请求存储缓存。
此外,当响应可复用时,源服务器不需要处理请求——因为它不需要解析和路由请求、根据 cookie 恢复会话、查询数据库以获取结果或渲染模板引擎。这减少了服务器上的负载。
不同种类的缓存
在 HTTP Caching 标准中,有两种不同类型的缓存:私有缓存和共享缓存。
私有缓存
私有缓存是绑定到特定客户端的缓存——通常是浏览器缓存。由于存储的响应不与其他客户端共享,因此私有缓存可以存储该用户的个性化响应。
另一方面,如果个性化内容存储在私有缓存以外的缓存中,那么其他用户可能能够检索到这些内容——这可能会导致无意的信息泄露。
如果响应包含个性化内容并且你只想将响应存储在私有缓存中,则必须指定 private 指令。
Cache-Control: private个性化内容通常由 cookie 控制,但 cookie 的存在并不能表明它是私有的,因此单独的 cookie 不会使响应成为私有的。
请注意,如果响应具有 Authorization 标头,则不能将其存储在私有缓存(或共享缓存,除非 Cache-Control 指定的是 public)中。
共享缓存
共享缓存位于客户端和服务器之间,可以存储能在用户之间共享的响应。共享缓存可以进一步细分为代理缓存和托管缓存。
代理缓存
除了访问控制的功能外,一些代理还实现了缓存以减少网络流量。这通常不由服务开发人员管理,因此必须由恰当的 HTTP 标头等控制
近年来,随着 HTTPS 变得越来越普遍,客户端/服务器通信变得加密,在许多情况下,路径中的代理缓存只能传输响应而不能充当缓存。 因此,在这种情况下,无需担心甚至无法看到响应的过时代理缓存的实现。
托管缓存
托管缓存由服务开发人员明确部署,以降低源服务器负载并有效地交付内容。示例包括反向代理、CDN 和 service worker 与缓存 API 的组合。
正向代理:替客户端出门,代替客户端发送请求(隐藏客户端) 反向代理:替服务器接客,代替服务器接收请求(隐藏服务器) 我快晕死了
启发式缓存
HTTP 旨在尽可能多地缓存,因此即使没有给出 Cache-Control,如果满足某些条件,响应也会被存储和重用。这称为启发式缓存。
HTTP/1.1 200 OK Content-Type: text/html Content-Length: 1024 Date: Tue, 22 Feb 2022 22:22:22 GMT Last-Modified: Tue, 22 Feb 2021 22:22:22 GMT
<!doctype html> …启发式缓存是在 Cache-Control 被广泛采用之前出现的一种解决方法,基本上所有响应都应明确指定 Cache-Control 标头。
不使用缓存
no-cache 指令不会阻止响应的存储,而是阻止在没有重新验证的情况下重用响应。
如果你不希望将响应存储在任何缓存中,请使用 no-store。
Cache-Control: no-store
但是,一般来说,实践中“不缓存”的原因满足以下情况:
出于隐私原因,不希望特定客户以外的任何人存储响应。 希望始终提供最新信息。 不知道在过时的实现中会发生什么。
不与其他用户共享
如果具有个性化内容的响应意外地对缓存的其他用户可见,那将是有问题的。
在这种情况下,使用 private 指令将导致个性化响应仅与特定客户端一起存储,而不会泄露给缓存的任何其他用户。
Cache-Control: private
每次都提供最新的内容
no-store 指令阻止存储响应,但不会删除相同 URL 的任何已存储响应。
换句话说,如果已经为特定 URL 存储了旧响应,则返回 no-store 不会阻止旧响应被重用。
但是,no-cache 指令将强制客户端在重用任何存储的响应之前发送验证请求。
Cache-Control: no-cache如果服务端不支持条件请求,你可以强制客户端每次都访问服务端,总是得到最新的 200 OK 响应。
兼容过时的实现
作为忽略 no-store 的过时实现的解决方法,你可能会看到使用了诸如以下内容的 kitchen-sink 标头:
Cache-Control: no-store, no-cache, max-age=0, must-revalidate, proxy-revalidate如果你关心的是共享缓存,你可以通过添加 private 来防止意外缓存:
Cache-Control: no-cache, private部分信息可能已经过时


