159

当我访问chesseng.herokuapp.com时,我得到一个响应头,看起来像

Cache-Control:private
Connection:keep-alive
Content-Encoding:gzip
Content-Type:text/css
Date:Tue, 16 Oct 2012 06:37:53 GMT
Last-Modified:Tue, 16 Oct 2012 03:13:38 GMT
Status:200 OK
transfer-encoding:chunked
Vary:Accept-Encoding
X-Rack-Cache:miss

然后我刷新页面并得到

Cache-Control:private
Connection:keep-alive
Date:Tue, 16 Oct 2012 06:20:49 GMT
Status:304 Not Modified
X-Rack-Cache:miss

所以看起来缓存正在工作。如果这适用于缓存,那么ExpiresCache-Control:max-age的意义何在。更令人困惑的是,当我在https://developers.google.com/speed/pagespeed/insights/测试页面时,它告诉我“利用浏览器缓存”。

4

4 回答 4

172
Cache-Control: private

表示响应消息的全部或部分是针对单个用户的,并且不得由共享缓存(例如代理服务器)缓存。

来自RFC2616 第 14.9.1 节

于 2012-10-16T07:17:27.377 回答
93

要回答您关于缓存为何起作用的问题,即使网络服务器不包含标头:

  • 过期: [a date]
  • 缓存控制: max-age=[seconds]

服务器恳请任何中间代理不要缓存内容(即,该项目应仅缓存在私有缓存中,即仅在您自己的本地计算机上):

  • 缓存控制:私有

但是服务器忘记包含任何类型的缓存提示:

  • 他们忘记包含Expires(因此浏览器知道在该日期之前使用缓存的副本)
  • 他们忘记包括Max-Age(所以浏览器知道缓存的项目可以使用多长时间)
  • 他们忘记包含电子标签(所以浏览器可以做一个有条件的请求)

但他们确实在回复中包含了 Last-Modified日期:

Last-Modified: Tue, 16 Oct 2012 03:13:38 GMT

因为浏览器知道文件被修改的日期,它可以执行一个条件请求。它将向服务器询问文件,但指示服务器仅在文件自 2012/10/16 3:13:38 以来已被修改时才发送文件:

GET / HTTP/1.1
If-Modified-Since: Tue, 16 Oct 2012 03:13:38 GMT

服务器收到请求,意识到客户端已经拥有最新版本。它不是发送 client 200 OK,然后是页面内容,而是告诉您您的缓存版本是好的:

304 Not Modified

您的浏览器确实不得不遭受向服务器发送请求并等待响应的往返延迟,但它确实省去了重新下载静态内容的麻烦。

为什么选择最大年龄?为什么过期

因为Last-Modified很烂。

并非服务器上的所有内容都有与之关联的日期。如果我正在即时构建页面,则没有与之关联的日期 -现在是. 但我完全愿意让用户将主页缓存 15 秒:

200 OK
Cache-Control: max-age=15

如果用户锤击F5,他们将继续获取缓存版本 15 秒。如果它是一个公司代理,那么在同一个 15 秒窗口中访问同一个页面的所有 67,198 个用户都将获得相同的内容 - 全部来自关闭缓存。为每个人赢得性能。

添加的优点Cache-Control: max-age是浏览器甚至不必执行“条件”请求。

  • 如果您仅指定Last-Modified,则浏览器必须执行If-Modified-Since请求并观察304 Not Modified响应
  • 如果您指定max-age,浏览器甚至不必遭受网络往返;内容将直接从缓存中出来。

“Cache-Control: max-age”和“Expires”的区别

Expires是现代Cache-Control: max-age标头的旧版(c. 1998)等价物:

  • Expires:你指定一个日期(呸)

  • max-age:你指定秒(善良)

  • 如果两者都指定,则浏览器使用max-age

      200 OK
      Cache-Control: max-age=60
      Expires: 20180403T192837 
    

1998 年之后编写的任何网站都不应再使用Expires,而应使用max-age.

什么是ETag?

ETag类似于Last-Modified,不同之处在于它不必是日期 - 它只需是something.

如果我从数据库中提取产品列表,服务器可以将最后一个rowversion作为 ETag 而不是日期发送:

200 OK
ETag: "247986"

我的 ETag 可以是静态资源(例如图像、js、css、字体)或缓存渲染页面的 SHA1 散列(即,这是 Mozilla MDN wiki 所做的;它们散列最终标记):

200 OK
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

与基于Last-Modified的条件请求完全一样:

GET / HTTP/1.1
If-Modified-Since: Tue, 16 Oct 2012 03:13:38 GMT

304 Not Modified

我可以根据 ETag执行条件请求:

GET / HTTP/1.1
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

304 Not Modified

AnETag优于,Last-Modified因为它适用于文件以外的事物,或者具有日期概念的事物。它只是

于 2018-04-03T18:54:31.150 回答
22

RFC 2616,第 14.9.1 节

表示响应消息的全部或部分是针对单个用户的,并且不能被共享缓存缓存...私有(非共享)缓存可以缓存响应。


浏览器可以使用这些信息。当然,当前的“用户”可能意味着很多东西:操作系统用户、浏览器用户(例如 Chrome 的配置文件)等。没有具体说明。

对我来说,一个更具体的例子Cache-Control: private代理服务器(通常有很多用户)不会缓存它。它适用于最终用户,而不是其他任何人。


仅供参考,RFC 明确表示这不提供安全性。它是关于显示正确的内容,而不是保护内容。

私有这个词的使用只控制响应可能被缓存的地方,并不能保证消息内容的私密性。

于 2014-02-01T20:07:24.593 回答
0

Expires entity-header 字段给出了响应被认为是陈旧的日期/时间。Cache-control:maxage 字段给出的年龄值(以秒为单位)大于哪个响应被认为是陈旧的。

尽管上面的标头字段为客户端提供了一种机制来决定是否向服务器发送请求。在某些情况下,客户端向服务器发送请求并且响应的年龄值大于最大值,这是否意味着服务器需要将资源发送给客户端?也许资源从未改变。

为了解决这个问题,HTTP1.1给出了last-modifided head。服务器将响应的最后修改日期提供给客户端。当客户端需要这个资源时,它会向服务器发送 If-Modified-Since 头字段。如果这个日期早于资源的修改日期,服务器会将资源发送给客户端并给出200代码。否则,它会返回304代码给客户端,这意味着客户端可以使用它缓存的资源。

于 2017-02-18T12:37:03.273 回答