什么是缓存控制:私有?

Posted

技术标签:

【中文标题】什么是缓存控制:私有?【英文标题】:What is Cache-Control: private? 【发布时间】:2012-10-06 04:51:54 【问题描述】:

当我访问 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/ 测试页面时,它告诉我“利用浏览器缓存”。

【问题讨论】:

查看此图***.com/a/49925190/3748498 【参考方案1】:
Cache-Control: private

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

来自RFC2616 section 14.9.1

【讨论】:

因为它被您的浏览器缓存了。您是响应的目标用户。 不,这不是因为Cache-Control:private 只声明共享缓存(例如代理缓存)不应缓存响应。 @Trejkaz 不,这实际上意味着单个用户。用户是一个帐户,它有自己的缓存所在的主目录。同一用户拥有的那些配置文件可以共享他们的缓存。正如你所发现的。但是,如果同一台计算机上的两个配置文件由不同的用户拥有,则不得共享其缓存,除非该缓存被视为共享缓存。 啊,所以它是每个用户在操作系统级别的。是的,我想知道的原因是因为 Chrome 的隐身窗口和非隐身窗口之间存在明显的信息泄漏,后者使用缓存来做到这一点。 @didibus proxy-revalidate 要求代理始终在每次访问时重新验证。 private 阻止代理缓存。【参考方案2】:

RFC 2616,section 14.9.1:

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


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

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


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

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

【讨论】:

私有(非共享)缓存可以缓存响应。这部分是关键。谢谢。【参考方案3】:

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

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

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

【讨论】:

【参考方案4】:

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

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

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

缓存控制:私有

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

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

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

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

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

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

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

304 Not Modified

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

为什么要最大年龄?为什么过期

因为 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 标头的旧版(约 1998 年)等价物:

Expires: 你指定一个日期(yuck)

max-age: 你指定秒(goodness)

如果都指定了,则浏览器使用max-age

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

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

什么是 ETag?

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

如果我从数据库中提取产品列表,服务器可以将最后一个 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

ETag 优于 Last-Modified,因为它适用于 文件 之外的东西,或者具有 日期 概念的东西。它只是

【讨论】:

太棒了!我为这个答案悬赏。如果cache-control 不存在会怎样?而你只有Etag?它是否仍然需要对服务器发出“条件请求”?我离线时看到的行为是它只是从缓存中返回。但是当它离线时,它不能发出那个有条件的请求。那么这是否意味着如果您保持离线状态,它是否会无限期缓存?我已经详细问过这个问题here。可以看看吗?

以上是关于什么是缓存控制:私有?的主要内容,如果未能解决你的问题,请参考以下文章

使用元标记设置缓存标头:始终在缓存控制响应中获取“私有”

swift类的私有访问控制的行为是啥?

私有git搭建

前端静态资源缓存控制策略浅析

缓存控制

通过HTTP Header控制缓存