Контроль кэша: нет хранилища, необходимо повторное подтверждение не отправлено клиентскому браузеру в IIS7 + ASP.NET MVC

Я пытаюсь убедиться, что определенная страница никогда не кэшируется и не отображается, когда пользователь нажимает кнопку "Назад". Этот очень высоко оцененный ответ (в настоящее время 1068 голосов) говорит, чтобы использовать:

Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");

Однако в IIS7 / ASP.NET MVC, когда я отправляю эти заголовки, клиент вместо этого видит эти заголовки ответа:

Cache-control: private, s-maxage=0 // that's not what I set them to
Pragma: no-cache
Expires: 0

Что случилось с заголовком контроля кеша? Перезаписывает ли что-то родное для IIS7 или ASP.NET? Я проверил свое решение, и у меня нет кода, который перезаписывает этот заголовок.

Когда я добавлю Response.Headers.Remove("Cache-Control"); Во-первых, это не имеет значения:

Response.Headers.Remove("Cache-Control");
Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");

Когда я добавляю [OutputCache] атрибут:

[OutputCache(Location = OutputCacheLocation.None)]
public ActionResult DoSomething()
{
   Response.Headers.Remove("Cache-Control");
   Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
   Response.AppendHeader("Pragma", "no-cache");
   Response.AppendHeader("Expires", "0");

   var model = DoSomething();
   return View(model);
}

Затем заголовки ответа клиента изменяются на:

Cache-control: no-cache
Pragma: no-cache
Expires: 0

Который ближе, но все еще не заголовки, которые я хочу отправить. Где эти заголовки переопределяются и как я могу это остановить?

РЕДАКТИРОВАТЬ: Я проверил, и неправильные заголовки отправляются в Chrome, FF, IE и Safari, так что это выглядит проблема сервера, а не проблема, связанная с браузером.

2 ответа

Решение

Методом проб и ошибок я обнаружил, что один из способов правильно установить заголовки для IIS7 в ASP.NET MVC:

Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");

Первая строка устанавливает Cache-control в no-cache, а вторая строка добавляет другие атрибуты no-store, must-revalidate,

Это может быть не единственный способ, но он предоставляет альтернативный метод, если более простой Response.AppendHeader("Cache-control", "no-cache, no-store, must-revalidate"); выходит из строя.

Другие связанные вопросы управления кэшем IIS7, которые могут быть решены этим:

Я хочу добавить что-то к ответу JK.:
Если вы устанавливаете для элемента управления кеша более ограничительное значение, чем оно есть, это нормально. (то есть: установка no-cache, когда это приватно)

Но, если вы хотите установить менее ограничительное значение, чем оно есть (то есть: установить значение private, когда оно не кэшируется), приведенный ниже код не будет работать:

Response.Cache.SetCacheability(HttpCacheability.Private);

Потому что метод SetCacheablitiy имеет этот код ниже и устанавливает флаг кеша только в том случае, если он более строгий:

if (s_cacheabilityValues[(int)cacheability] < s_cacheabilityValues[(int)_cacheability]) {
    Dirtied();
   _cacheability = cacheability;
}

Чтобы преодолеть это в.net mvc, вам нужно получить экземпляр HttpResponseMessage и назначить CacheControlHeaderValue к его Headers.CacheControl значение:

actionExecutedContext.Response.Headers.CacheControl = new CacheControlHeaderValue
                                   {
                                       MaxAge = TimeSpan.FromSeconds(3600),
                                       Private = true
                                   };

Экземпляр HttpResponseMessage доступно в фильтрах действий. Вы можете написать фильтр действий для установки значений заголовка кэша, например так:

public class ClientSideCacheAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        var response = actionExecutedContext.ActionContext.Response;
        response.Headers.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue
        {
            MaxAge = TimeSpan.FromSeconds(9999),
            Private = true,
        };
    }
}

Если вам нужны эти заголовки глобально в вашем приложении MVC. Добавьте этот класс.

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class CustomHeaders : System.Web.Mvc.ActionFilterAttribute
{
    [OutputCache(Location = System.Web.UI.OutputCacheLocation.None)]
    public override void OnActionExecuted(ActionExecutedContext context)
    {
        context.RequestContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        context.RequestContext.HttpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate");
        context.RequestContext.HttpContext.Response.AppendHeader("Pragma", "no-cache");
        context.RequestContext.HttpContext.Response.AppendHeader("Expires", "0");

        base.OnActionExecuted(context);
    }
}

Для глобального использования добавьте его в FilterConfig.

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new CustomHeaders());
    }
}

Или используйте эти заголовки только на конкретном контроллере.

[Authorize]
[CustomHeaders]
public class HomeController : Controller
{
    [AllowAnonymous]
    public ActionResult Index()

Примечание: вы можете использовать IIS и web.config для других заголовков. Например, для статического контента, такого как ваши пакеты (jquery,bootstrap). Поищите в этих разделах customheaders, staticcontent.

Другие вопросы по тегам