目录
通过重用以前获取的资源,可以显着提高网站和应用程序的性能。
Web 缓存(Web caches )减少了延迟和网络流量,从而减少了显示资源表示所需的时间。
HTTP 缓存(HTTP caching)使网站响应更快。
缓存类型
缓存是一种技术,可以存储给定资源的副本,并在请求时将其提供回来。当 Web 缓存在其存储中有请求的资源时,它会拦截该请求并返回所存储资源的副本,而不是从原始服务器重新下载该资源。这实现了几个目标:
- 它减轻了服务器的负载,因为它不需要自己为所有客户端提供服务
- 通过更接近客户端来提高性能。换句话说,将资源传回所需的时间更少。
对于网站,Web 缓存是实现高性能的主要组成部分。但是,必须正确配置缓存功能,因为并非所有资源都永远保持相同:重要的是仅缓存资源直到它发生变化,而不是更长。
有几种类型的缓存。这些可以分为两大类:共享缓存和私有缓存。
- 共享缓存(shared caches)是一个高速缓存用于通过一个以上的用户复用存储的响应。
- 私有缓存(private caches)专用于单个用户。
本页面将主要讨论浏览器和代理缓存,但也有部署在 Web 服务器上的网关缓存(gateway caches)、CDN、反向代理缓存(reverse proxy caches)和负载平衡器( load balancers),以提高网站和 Web 应用程序的可靠性、性能和扩展性。
私有浏览器缓存(Private browser caches)
私有缓存专供单个用户使用。您可能已经在浏览器的设置中看到了“缓存”。浏览器缓存保存用户通过HTTP下载的所有文档。此缓存用于使访问过的文档可用于后退/前进导航、保存、作为源查看等,而无需额外访问服务器。它还改进了缓存内容的离线浏览。
共享代理缓存(Shared proxy caches)
共享缓存是一种缓存,用于存储可供多个用户重用的响应。例如,Internet 服务提供商 (ISP) 或您的公司可能已将 Web 代理设置为本地网络基础架构的一部分来为许多用户提供服务,以便多次重复使用流行资源,从而减少网络流量和延迟。
缓存操作的目标
HTTP 缓存是可选的,但通常是可取的。HTTP 缓存通常仅限于缓存对请求方法的响应GET;他们可能会拒绝其他方法。主缓存键由请求方法( request method)和目标 URI( target URI) 组成(通常只使用 URI,因为只有GET请求是缓存目标)。
缓存条目的常见形式有:
- 检索请求的成功结果:200对GET包含 HTML 文档、图像或文件等资源的请求的(OK)响应。
- 永久重定向:(永久301移动)响应。
- 错误响应:(404未找到)结果页面。
- 不完整的结果:(206部分内容)响应。
- 除了GET定义了适合用作缓存键的内容之外的响应。
如果请求是内容协商的目标,则缓存条目还可以由多个存储的响应组成,这些响应由辅助密钥区分。有关更多详细信息,请参阅下面有关(Vary)[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary]标题的信息。
控制缓存(Controlling caching)
Cache-Control头
Cache-Control HTTP / 1.1通用头字段被用于为请求和响应缓存机制指定指令。使用此标头通过它提供的各种指令定义缓存策略。
无缓存(No caching)
缓存不应存储有关客户端请求或服务器响应的任何内容。请求被发送到服务器,并且每次都下载完整的响应。
Cache-Control: no-store
缓存但重新验证(Cache but revalidate)
在释放缓存副本之前,缓存会将请求发送到源服务器进行验证。
Cache-Control: no-cache
私有和公共缓存(Private and public caches)
“public”指令表示响应可以被任何缓存缓存。如果现在应该缓存具有 HTTP 身份验证或通常不可缓存的响应状态代码的页面,这会很有用。
“private”表示响应仅供单个用户使用,不得由共享缓存存储。在这种情况下,私有浏览器缓存可能会存储响应。
Cache-Control: private
Cache-Control: public
到期(Expiration)
这里最重要的指令是max-age=,这是资源被视为新鲜(considered fresh)的最长时间。(请参阅本文档中的“新鲜度”部分以了解此处“新鲜”的含义。)该指令与请求的时间相关,并覆盖Expires标头(如果已设置)。对于应用程序中不会发生变化的文件,通常可以使用主动缓存。这包括静态文件,例如图像、CSS 文件和 JavaScript 文件。
有关更多详细信息,另请参阅下面的新鲜度部分。
Cache-Control: max-age=31536000
验证(Validation)
当使用 " must-revalidate" 指令时,缓存必须在使用它们之前验证陈旧资源的状态。不应使用过期的资源。有关更多详细信息,请参阅下面的验证部分。请参阅下面的“新鲜度”部分,了解我们所说的“陈旧资源”是什么意思。
Cache-Control: must-revalidate
Pragma头
Pragma是一个 HTTP/1.0 标头。 Pragma: no-cache就像 Cache-Control: no-cache 它强制缓存在释放缓存副本之前将请求提交给源服务器进行验证。但是,Pragma 没有为 HTTP 响应指定,因此不是通用 HTTP/1.1Cache-Control标头的可靠替代品。
Pragma 应该仅用于与 HTTP/1.0 缓存的向后兼容,其中 Cache-Control HTTP/1.1 标头尚不存在。
新鲜度(Freshness)
一旦资源存储在缓存中,理论上它可以永远由缓存提供服务。缓存具有有限的存储空间,因而项目会定期从存储中移除。这个过程称为缓存驱逐(cache eviction)。此外,服务器上的某些资源可能会发生变化,因而缓存也要更新。由于 HTTP 是一种客户端-服务器协议,当资源发生变化时,服务器无法联系缓存和客户端;它们必须传达一个资源的到期时间。在这个过期时间之前,资源是新鲜(fresh)的;在过期时间之后,资源是陈旧的(stale). 驱逐算法通常会优先考虑新鲜资源而不是陈旧资源。请注意,陈旧的资源不会被驱逐或忽略;当缓存收到对陈旧资源的请求时,它会转发带If-None-Match的请求以检查它是否实际上仍然是新鲜的。如果还新鲜,服务器返回一个304(Not Modified)头而不发送请求资源的主体,节省一些带宽。
以下是此过程的示例,其中包含共享缓存代理:
新鲜度生命周期是根据几个标头计算的。
- 如果Cache-Control: max-age=N指定了标头,则新鲜度生存期等于 N。
- 如果此标头(max-age)不存在(这种情况很常见),则缓存会检查Expires标头是否存在。如果Expires标头存在,则其值减去Date标头的值确定新鲜度生存期。
启发式新鲜度检查(Heuristic freshness checking)
如果源服务器未明确指定新鲜度(例如,使用Cache-Control 或Expires标头),则可以使用启发式方法。
如果是这种情况,请查找Last-Modified标头。如果标头存在,则缓存的新鲜度生存期等于Date标头值减去Last-modified标头值除以 10。过期时间计算如下:
expirationTime = responseTime + freshnessLifetime - currentAge
这里的responseTime是根据浏览器收到响应的时间。有关更多信息,请参阅 RFC 7234: Hypertext Transfer Protocol (HTTP/1.1): 4.2.2. Calculating Heuristic Freshness.
更新资源(Revved resources)
我们使用缓存资源越多,网站的响应能力和性能就会越好。为了优化缓存资源的使用,良好的实践建议设置尽可能未来过期时间。这对于定期或经常更新的资源是合理的,但对于很少或不经常更新的资源来说是有问题的。后者是最能从缓存资源中受益的资源,但它们很难更新。这是每个网页包含和链接的技术资源的典型特征:JavaScript 和 CSS 文件很少更改,但是当它们发生更改时,您希望它们能够快速更新。
Web 开发人员发明了一种技术,Steve Souders 称之为 加速. 不经常更新的文件以特定方式命名:在它们的 URL 中,通常在文件名中,添加修订(或版本)号。这样,资源的每个新版本都被视为一种资源,它本身永远不会改变,并且可以在很远的将来(通常为一年甚至更长)到期。要获得新版本,必须更改指向资源的所有链接。这就是这种方法的缺点:Web 开发人员通常会使用工具链来处理而增加的复杂性。当偶尔更改的资源发生更改时,它们会引起对经常变化的资源的额外更改。后者被读取时,前者的新版本也会被读取。
这种技术还有一个额外的好处:同时更新两个缓存资源会避免一个资源的过时版本与另一个资源的新版本结合使用的情况。当网站具有相互依赖的 CSS 样式表或 JS 脚本时,这非常重要,这意味着它们相互依赖,因为它们引用相同的 HTML 元素。
添加到 revved 资源的修订版本不需要是像 1.1.3 这样的经典修订字符串,甚至不需要是一组单调增长的数字。它只需要防止冲突,例如哈希或日期。
缓存验证(Cache validation)
当已达到缓存资源的到期时间时,资源将被验证或再次获取。只有在服务器提供强验证器或弱验证器时才能进行验证。
当用户按下重新加载按钮时触发重新验证。如果缓存的响应包含 " Cache-Control: must-revalidate" 标头,它也会在正常浏览期间触发。您还可以使用Advanced->Cache选项面板中的缓存验证首选项,它提供了在每次加载资源时强制进行验证的选项。
ETags
ETag响应报头是对用户代理不透明(opaque-to-the-useragent)可以使用作为强验证值。这意味着 HTTP 用户代理,例如浏览器,不知道这个字符串代表什么,也无法预测它的值是什么。如果ETag标头是资源响应的一部分,客户端可以If-None-Match在未来请求的标头中发出一个,以验证缓存的资源。
Last-Modified
的Last-Modified响应报头可以被用作弱验证器。它被认为是弱的,因为它只有 1 秒的分辨率。如果Last-Modified响应中存在标头,则客户端可以发出If-Modified-Since请求标头以验证缓存的文档。
当发出验证请求时,服务器可以忽略验证请求并以正常的 200 OK 响应,或者它可以返回 304 Not Modified(带有空正文)以指示浏览器使用其缓存副本。后者的响应还可以包括更新缓存资源到期时间的标头。
不同的反应(Varying responses)
Vary HTTP响应报头确定如何匹配未来请求头,以决定一个缓存的响应是否可以使用或新鲜一个必须从源服务器来请求。
当缓存接收到具有Vary标头字段的请求时,默认情况下它不得使用缓存响应,除非Vary标头中指定的所有标头字段在原始(缓存)请求和新请求中均匹配。
此功能通常用于允许以未压缩和(各种)压缩形式缓存资源,并根据它们支持的编码适当地为用户代理提供服务。例如,服务器可以设置 Vary: Accept-Encoding 确保为所有指定支持特定编码集的请求缓存一个单独版本的资源,例如:Accept-Encoding: gzip,deflate,sdch。
Vary: Accept-Encoding
注意:Vary小心使用。它很容易降低缓存的有效性!缓存服务器应该使用规范化来减少重复的缓存条目和对源服务器的不必要的请求。当您使用Vary具有多个值的标头和标头值时尤其如此。
该Vary头也可以是有益的服务不同的内容为桌面和移动用户,或允许搜索引擎发现一个页面的移动版本(也许还告诉他们,没有刻意伪装)。这通常是通过Vary:User-Agent头实现的,因为移动和桌面客户端的User-Agent头值不同。
Vary: User-Agent
规范化(Normalization)
如上所述,高速缓存服务器只默认匹配报头和报头值恰好相同的请求。这意味着将向源站发出请求都可能因为不同用户代理这一点点区别而创建一个新缓存。
例如,默认情况下,以下所有操作都会导致对源站的单独请求和单独的缓存:
Accept-Encoding: gzip,deflate,sdch
Accept-Encoding: gzip,deflate
Accept-Encoding: gzip
即使原始服务器可能会响应并存储所有请求(gzip)的相同资源,也是如此!
为了避免不必要的请求和重复的缓存条目,缓存服务器应该使用 规范化来预处理请求并只缓存需要的文件。例如,在 的情况下 Accept-Encoding,您可以gzip 在进一步处理之前检查标头中的 和 其他压缩类型,否则取消设置标头。在“伪代码”中,这可能如下所示:
// Normalize Accept-Encoding
if (req.http.Accept-Encoding) {
if (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
}
// elsif other encoding types to check
else {
unset req.http.Accept-Encoding;
}
}
User-Agent比 有更多的变化Accept-Encoding。因此,如果Vary: User-Agent 用于缓存文件的移动/桌面变体,您检查请求的User-Agent标头中是否存在 “mobile"和"desktop”,然后清除它。
相关头记录
Age
Age 消息头里包含对象在缓存代理中存贮的时长,以秒为单位。.
Age的值通常接近于0。表示此对象刚刚从原始服务器获取不久;其他的值则是表示代理服务器当前的系统时间与此应答中的通用头 Date 的值之差。
语法
Age: <delta-seconds>
指令
- <delta-seconds>
一个非负整数,表示对象在缓存代理服务器中存贮的时长,以秒为单位。
示例
Age: 24
Expires
Expires 响应头包含日期/时间, 即在此时候之后,响应过期。
无效的日期,比如 0, 代表着过去的日期,即该资源已经过期。
如果在Cache-Control响应头设置了 “max-age” 或者 “s-max-age” 指令,那么 Expires 头会被忽略。
语法
Expires: <http-date>
指令
- <http-date>
一个 HTTP-日期 时间戳
示例
Expires: Wed, 21 Oct 2015 07:28:00 GMT
php获取该时间格式
gmdate("D, d M Y H:i:s", time()+604800)." GMT"
Date
Date通用HTTP报头包含在该消息起源的日期和时间。
语法
Date: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
示例
Date: Wed, 21 Oct 2015 07:28:00 GMT
参考
HTTP caching
expire
Age