Почему HttpCacheability.Private подавляет ETags?
При написании пользовательского IHttpHandler я сталкивался с поведением, которое я не ожидал относительно объекта HttpCachePolicy.
Мой обработчик вычисляет и устанавливает сущность-тег (используя метод SetETag на HttpCachePolicy, связанный с текущим объектом ответа). Если я настрою кеш-контроль на общедоступный, используя метод SetCacheability, все работает как шарм, и сервер отправляет его по заголовку e-tag. Если я установил его в закрытый, заголовок 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")
Обновление. Можно добавить заголовок ETag вручную при работе в IIS7, я подозреваю, что это связано с плотной интеграцией между ASP.NET и конвейером IIS7.
Разъяснение. Это долгий вопрос, но основной вопрос заключается в следующем: почему ASP.NET делает это, как я могу обойти его, и должен ли я?
Обновить: я соглашусь ответить Тони, поскольку он по существу исправлен (иди Тони!). Я обнаружил, что если вы хотите полностью эмулировать HttpCacheability.Private, вы можете установить кешируемость ServerAndPrivate, но у вас также есть кэш вызовов. SetOmitVaryStar (true), иначе кеш будет добавлять заголовок Vary: * к выходу, и вы этого не хотите. Я отредактирую это в ответ, когда получаю разрешения на редактирование (или, если вы видите, что это Тони, возможно, вы можете отредактировать свой ответ, чтобы включить этот вызов?)
Ответы
Ответ 1
Я думаю, вам нужно использовать HttpCacheability.ServerAndPrivate
Это должно дать вам управление кешем: личное в заголовках и позволяет установить ETag.
Документация по этому вопросу должна быть немного лучше.
Изменить: Маркус обнаружил, что у вас также есть кэш вызовов. SetOmitVaryStar (true), иначе кеш добавит заголовок Vary: * к выходу, и вы этого не хотите.
Ответ 2
К сожалению, если вы посмотрите на System.Web.HttpCachePolicy.UpdateCachedHeaders()
в .NET Reflector, вы увидите, что есть оператор if, специально проверяющий, что Cacheability не является приватным, прежде чем делать какие-либо вещи ETag. В любом случае, я всегда обнаружил, что Last-Modified/If-Modified-Since
хорошо работает для наших данных и в любом случае немного легче контролировать в Fiddler.
Ответ 3
Если вы, как я, вы недовольны описанным здесь обходным путем использования Cacheability.ServerAndPrivate, и вы действительно хотите использовать Private вместо этого - возможно, потому, что вы индивидуально настраиваете страницы для пользователей, и нет смысла кэшировать на сервере - то, по крайней мере, в .NET 3.5 вы можете установить ETag через Response.Headers.Add, и это отлично работает.
N.B. если вы это сделаете, вам придется реализовать сравнение заголовков клиентов самостоятельно и обработку ответа HTTP 304 - не уверен, что .NET позаботится об этом для вас при нормальных обстоятельствах.