为什么HttpCacheability.Private会抑制ETag?

时间:2008-08-28 17:08:59

标签: c# asp.net http caching

在编写自定义IHttpHandler时,我遇到了一个我没想到的关于HttpCachePolicy对象的行为。

我的处理程序计算并设置一个实体标记(使用与当前响应对象关联的HttpCachePolicy上的SetETag方法)。如果我使用SetCacheability方法将缓存控件设置为public,则所有内容都像魅力一样,服务器会沿着e-tag标头发送。如果我将其设置为私有,则将禁止使用电子标签。

也许我只是看起来不够努力,但我没有在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; } }
}

将返回

Cache-Control: private
Content-Type: text/plain; charset=utf-8
Content-Length: 11

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

Cache-Control: public
Content-Type: text/plain; charset=utf-8
Content-Length: 11
Etag: "static"

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

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

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

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

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

3 个答案:

答案 0 :(得分:17)

我认为您需要使用HttpCacheability.ServerAndPrivate

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

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

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

答案 1 :(得分:3)

不幸的是,如果你在.NET Reflector中查看System.Web.HttpCachePolicy.UpdateCachedHeaders(),你会发现在执行任何ETag之前,有一个if语句专门检查Cacheability是否为Private。在任何情况下,我总是发现Last-Modified/If-Modified-Since适用于我们的数据,并且在Fiddler中更容易监控。

答案 2 :(得分:0)

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

N.B。如果你这样做,你必须自己实现客户端头的比较和HTTP 304响应处理 - 不确定.NET是否在正常情况下为你处理这个问题。