缓存的作用
Web 缓存是可以自动保存常见文档副本的 HTTP 设备。当 Web 请求抵达缓存时, 如果本地有“已缓存的”副本,就可以从本地存储设备而不是原始服务器中提取这 个文档。使用缓存有下列优点。
- 缓存减少了冗余的数据传输,节省了你的网络费用。
- 缓存缓解了网络瓶颈的问题。不需要更多的带宽就能够更快地加载页面。
- 缓存降低了对原始服务器的要求。服务器可以更快地响应,避免过载的出现。 • 缓存降低了距离时延,因为从较远的地方加载页面会更慢一些。
命中和未命中的
可以用已有的副本为某些到达缓存的请求提供服务。这被称为缓存命中(cache hit),其他一些到达缓存的请求可能会由于没有副本可用,而被转发 给原始服务器。这被称为缓存未命中(cache miss)。
再验证
原始服务器的内容可能会发生变化,缓存要不时对其进行检测,看看它们保存的 副本是否仍是服务器上最新的副本。这些“新鲜度检测”被称为 HTTP 再验证 (revalidation)
304 (Not Modified)
缓存对缓存的副本进行再验证时,会向原始服务器发送一个小的再验证请求。如果 内容没有变化,服务器会以一个小的 304 Not Modified 进行响应。只要缓存知道副 本仍然有效,就会再次将副本标识为暂时新鲜的,并将副本提供给客户端,这被称作再验证命中(revalidate hit)或缓慢命中(slow hit)。
HTTP 为我们提供了几个用来对已缓存对象进行再验证的工具,但最常用的是 If- Modified-Since 首部。这里列出了在 3 种情况下(服务器内容未被修改,服务器内容已被修改,或者服务 器上的对象被删除了)服务器收到 GET If-Modified-Since 请求时会发生的情况:
- 再验证命中
如果服务器对象未被修改,服务器会向客户端发送一个小的 HTTP 304 Not Modified 响应。
成功的再验证比缓存未命中要快,失败的再验证几乎和未命中的速度一样
HTTP 使用 If-Modified-Since 首部进行再验证
- 再验证未命中 如果服务器对象与已缓存副本不同,服务器向客户端发送一条普通的、带有完整 内容的 HTTP 200 OK 响应。
- 对象被删除 如果服务器对象已经被删除了,服务器就回送一个 404 Not Found 响应,缓存也 会将其副本删除。
缓存的处理步骤
(1) 接收——缓存从网络中读取抵达的请求报文。
(2) 解析——缓存对报文进行解析,提取出 URL 和各种首部。
(3) 查询——缓存查看是否有本地副本可用,如果没有,就获取一份副本(并将其保
存在本地)。
(4) 新鲜度检测——缓存查看已缓存副本是否足够新鲜,如果不是,就询问服务器是
否有任何更新。
(5) 创建响应——缓存会用新的首部和已缓存的主体来构建一条响应报文。
(6) 发送——缓存通过网络将响应发回给客户端。
(7) 日志——缓存可选地创建一个日志文件条目来描述这个事务。
HTTP 协议要求行为正确的缓存返回下列内容之一:
- “足够新鲜”的已缓存副本;
- 与服务器进行过再验证,确认其仍然新鲜的已缓存副本;
- 如果需要与之进行再验证的原始服务器出故障了,就返回一条错误报文 14;
- 附有警告信息说明内容可能不正确的已缓存副本。
控制缓存
服务器可以通过 HTTP 定义的几种方式来指定在文档过期之前可以将其缓存多长时 间。按照优先级递减的顺序,服务器可以:
- 附加一个 Cache-Control: no-store 首部到响应中去;
标识为 no-store 的响应会禁止缓存对响应进行复制。缓存通常会像非缓存代理服 务器一样,向客户端转发一条 no-store 响应,然后删除对象。
- 附加一个 Cache-Control: no-cache 首部到响应中去;
标识为 no-cache 的响应实际上是可以存储在本地缓存区中的。只是在与原始服 务器进行新鲜度再验证之前,缓存不能将其提供给客户端使用。
- 附加一个 Cache-Control: must-revalidate 首部到响应中去;
Cache-Control: must-revalidate 响应首部告诉缓存,在事先没有跟原始服务 器进行再验证的情况下,不能提供这个对象的陈旧副本。
- 附加一个 Cache-Control: max-age 首部到响应中去;
Cache-Control: max-age 首部表示的是从服务器将文档传来之时起,可以认为此 文档处于新鲜状态的秒数。还有一个 s-maxage 首部(注意 maxage 的中间没有连 字符),其行为与 max-age 类似,但仅适用于共享(公有)缓存:
Cache-Control: max-age=3600 Cache-Control: s-maxage=3600服务器可以请求缓存不要缓存文档,或者将最大使用期设置为零,从而在每次访问 的时候都进行刷新:Cache-Control: max-age=0 Cache-Control: s-maxage=0
- 附加一个 Expires 日期首部到响应中去;
不推荐使用 Expires 首部,它指定的是实际的过期日期而不是秒数。HTTP 设计者 后来认为,由于很多服务器的时钟都不同步,或者不正确,所以最好还是用剩余秒 数,而不是绝对时间来表示过期时间。
- 不附加过期信息,让缓存确定自己的过期日期。
如果响应中没有 Cache-Control: max-age 首部,也没有 Expires 首部,缓存可 以计算出一个试探性最大使用期。LM-Factor 算法是一种很常用的试探性过期算法,如果文档中包含了最后修改日期, 就可以使用这种算法。LM-Factor 算法将最后修改日期作为依据,来估计文档有多 么易变。算法的逻辑如下所示。• 如果已缓存文档最后一次修改发生在很久以前,它可能会是一份稳定的文档,不太会突然发生变化,因此将其继续保存在缓存中会比较安全。• 如果已缓存文挡最近被修改过,就说明它很可能会频繁地发生变化,因此在与服务器进行再验证之前,只应该将其缓存很短一段时间。