为啥 HttpCacheability.Private 会抑制 ETag?

Posted

技术标签:

【中文标题】为啥 HttpCacheability.Private 会抑制 ETag?【英文标题】:Why does HttpCacheability.Private suppress ETags?为什么 HttpCacheability.Private 会抑制 ETag? 【发布时间】:2010-09-07 03:56:50 【问题描述】:

在编写自定义 IHttpHandler 时,我遇到了与 HttpCachePolicy 对象有关的意外行为。

我的处理程序计算并设置一个实体标签(使用与当前响应对象关联的 HttpCachePolicy 上的 SetETag 方法)。如果我使用 SetCacheability 方法将缓存控制设置为公共,那么一切都会像魅力一样工作,服务器会沿着电子标签标头发送。如果我将其设置为私有,则电子标签标题将被禁止。

也许我只是看起来不够努力,但我在 HTTP/1.1 规范中没有看到任何可以证明这种行为合理的东西。为什么不希望将 E-Tag 发送到浏览器同时仍禁止代理存储数据?

using System;
using System.Web;

public class Handler : IHttpHandler 
    public void ProcessRequest (HttpContext ctx) 
        ctx.Response.Cache.SetCacheability(HttpCacheability.Private);
        ctx.Response.Cache.SetETag("\"static\"");
        ctx.Response.ContentType = "text/plain";
        ctx.Response.Write("Hello World");
    

    public bool IsReusable  get  return true;  

会回来

缓存控制:私有 内容类型:文本/纯文本;字符集=utf-8 内容长度:11

但如果我们将其更改为公开,它会返回

缓存控制:公共 内容类型:文本/纯文本;字符集=utf-8 内容长度:11 Etag:“静态”

到目前为止,我已经在 ASP.NET 开发服务器和 IIS6 上运行它,结果相同。此外,我无法使用

显式设置 ETag
Response.AppendHeader("ETag", "static")

更新:在 IIS7 中运行时可以手动附加 ETag 标头,我怀疑这是由于 ASP.NET 和 IIS7 管道之间的紧密集成造成的。

澄清:这是一个很长的问题,但核心问题是:为什么 ASP.NET 会这样做,我该如何解决,我应该如何解决? p>

更新:我会接受Tony's answer,因为它基本上是正确的(去Tony!)。我发现如果你想完全模拟 HttpCacheability.Private 你可以将缓存能力设置为 ServerAndPrivate 但你也可以调用 cache.SetOmitVaryStar(true) 否则缓存将添加 Vary: * 标头到输出,你不想要那个。当我获得编辑权限时,我会将其编辑到答案中(或者如果您看到这个 Tony,也许您可​​以编辑您的答案以包含该呼叫?)

【问题讨论】:

【参考方案1】:

我认为你需要使用 HttpCacheability.ServerAndPrivate

这应该给你 cache-control: private 在标题中并让你设置一个 ETag。

这方面的文档需要更好一些。

编辑: Markus 发现您也调用了 cache.SetOmitVaryStar(true) 否则缓存会将 Vary: * 标头添加到输出中,而您不希望这样。

【讨论】:

我不知道this answer 到另一个问题是否描述了@Markus 将调用添加到SetOmitVaryStar() 的原因,但从 ASP.NET 4.0 开始可能不再需要它。 【参考方案2】:

不幸的是,如果您查看 .NET Reflector 中的System.Web.HttpCachePolicy.UpdateCachedHeaders(),您会发现在执行任何 ETag 内容之前,有一个 if 语句专门检查 Cacheability 是否不是私有的。无论如何,我一直发现Last-Modified/If-Modified-Since 非常适合我们的数据,而且无论如何在 Fiddler 中更容易监控。

【讨论】:

【参考方案3】:

如果您像我一样对此处提到的使用 Cacheability.ServerAndPrivate 的解决方法不满意,并且您真的想使用 Private 代替 - 可能是因为您正在为用户单独自定义页面并且在服务器上缓存没有意义 -那么至少在 .NET 3.5 中,您可以通过 Response.Headers.Add 设置 ETag,这可以正常工作。

注意如果您这样做,您必须自己实现客户端标头的比较和 HTTP 304 响应处理 - 不确定 .NET 在正常情况下是否会为您处理。

【讨论】:

您可以随时调用HttpCachePolicy.SetNoServerCaching 来禁用输出缓存(即服务器缓存)。这会覆盖HttpCacheability.ServerAndPrivate 的“服务器”部分。 @WilliamGross 这应该是公认的答案!谢谢。

以上是关于为啥 HttpCacheability.Private 会抑制 ETag?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?

为啥 CAP 定理中的 RDBMS 分区不能容忍,为啥它可用?