为什么 HttpCacheability.Private 会抑制 ETag?
题
在编写自定义 IHttpHandler 时,我遇到了有关 HttpCachePolicy 对象的意外行为。
我的处理程序计算并设置实体标记(使用与当前响应对象关联的 HttpCachePolicy 上的 SetETag 方法)。如果我使用 SetCacheability 方法将缓存控制设置为公共,一切都会像魅力一样工作,并且服务器会沿着电子标签标头发送。如果我将其设置为私有,电子标签标头将被抑制。
也许我只是没有仔细研究,但我没有在 HTTP/1.1 规范中看到任何可以证明这种行为合理的内容。为什么您不想将电子标签发送到浏览器,同时仍禁止代理存储数据?
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 会这样做,我该如何解决它,我应该这样做吗?
更新: :我要接受 托尼的回答 因为它本质上是正确的(去托尼!)。我发现,如果你想完全模拟 HttpCacheability.Private,你可以将可缓存性设置为 ServerAndPrivate,但你也有调用缓存。设置省略变量星号(true) 否则缓存将添加 各不相同:* 标头到输出,而您不希望这样。当我获得编辑权限时,我会将其编辑到答案中(或者如果您看到这个托尼,也许您可以编辑您的答案以包含该呼叫?)
解决方案
我认为你需要使用 HttpCacheability.ServerAndPrivate
这应该给你缓存控制:标头中的 private 并允许您设置 ETag。
关于这方面的文档需要更好一点。
编辑: Markus 发现你还调用了cache.SetOmitVaryStar(true) 否则缓存会添加Vary:* 标头到输出,但你不希望这样。
其他提示
不幸的是,如果你看 System.Web.HttpCachePolicy.UpdateCachedHeaders()
在 .NET Reflector 中,您会看到有一个 if 语句专门在执行任何 ETag 操作之前检查可缓存性是否不是私有的。无论如何,我总是发现 Last-Modified/If-Modified-Since
对于我们的数据来说效果很好,并且在 Fiddler 中更容易监控。
如果像我一样,您对这里提到的使用 Cacheability.ServerAndPrivate 的解决方法不满意,并且您确实想使用 Private - 可能是因为您正在为用户单独定制页面,并且在服务器上缓存没有意义 - 那么至少在 .NET 3.5 中,您可以通过 Response.Headers.Add 设置 ETag,效果很好。
注意:如果你这样做,你必须自己实现客户端标头的比较和 HTTP 304 响应处理 - 不确定 .NET 在正常情况下是否会为你处理这个问题。