我使用 Apache 2.4.3 作为反向代理,因为它宣称符合 RFC 2616。我的应用程序使用如下标头在代理上启用缓存:
Cache-Control: public, s-maxage=0
Expires: ... (+1 day)
X-Group: A
Vary: X-Group
ETag: W/"foo1"
在第一个请求预热缓存之后,如果我的应用程序更改为以下响应:
Cache-Control: public, s-maxage=0
Expires: ... (+1 day)
X-Group: B
Vary: X-Group
ETag: W/"foo2"
如果 Apache 的 If-None-Match 标头与源生成的 ETag 匹配,则应用程序将响应 304 Not Modified。但是,Apache 随后会缓存第二个 200 响应,并且取代用新的响应缓存“foo1”记录,而不是用不同的 ETag 缓存两个响应。因此,If-None-Match: W/"foo1", W/"foo2"
下一个重新验证请求只是If-None-Match: W/"foo2"
。因此,缓存不断丢失,而不是始终命中。
来自 RFC 2616 第 12.1 节:
但是,原始服务器不限于这些维度,并且可以根据请求的任何方面改变响应,包括请求标头字段之外的信息或本规范未定义的扩展标头字段内的信息。
我已经尝试了以下 Vary 组合:
Vary: X-Foo
Vary: *
Vary: User-Agent
我也尝试了强 ETag 和弱 ETag,但无论如何我都无法让 Apache 同时缓存这两个响应,它总是保存前一个。如果它无法保存页面的多个变体,那么 ETag 就毫无用处,Last-Modified 也一样好用。
来自 Apache 2.4 文档:
mod_cache 实现了符合 RFC 2616 的 HTTP 内容缓存过滤器,支持缓存包含 Vary 标头的内容协商响应。
请注意,它说的是复数“响应”。是我误解了 HTTP 规范,还是 Apache 2.4 毕竟没有完全支持 ETag?
答案1
您举了几个这样的示例:
Cache-Control: public, s-maxage=0
Expires: ... (+1 day)
X-Group: A
Vary: X-Group
ETag: W/"foo1"
我特别注意到了Vary: X-Group
标头。这是X-Group
请求标头还是响应标头?
按照RFC 2616 第 14.44 节,Vary
应列出任何要求标头会导致与原始服务器不同的内容表示。从您的示例来看,我怀疑X-Group
可能是响应标头,在这种情况下,mod_cache 不会存储给定资源的多个版本。
您可以尝试设置Vary: If-None-Match
,这将使 mod_cache 为每个 ETag 存储资源的一个版本。诚然,我还没有尝试过。假设它有效,一个缺点是来自任何客户端的第一个请求都将是缓存未命中。