У меня есть метод действия, который я хочу кэшировать:
[OutputCache(Duration=60*5, Location=OutputCacheLocation.Any, VaryByCustom="index")]
public ActionResult Index()
{
return View();
}
При таком подходе:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
context.Response.Cache.SetOmitVaryStar(true);
context.Response.Cache.VaryByHeaders["Cookie"] = true;
if (User.Identity.IsAuthenticated)
{
Debug.Print("Authenticated");
context.Response.Cache.SetNoServerCaching();
context.Response.Cache.SetCacheability(HttpCacheability.Private);
return null;
}
else
{
Debug.Print("Non authenticated");
return custom;
}
}
Идея состояла в том, чтобы сохранить кэшированную версию страницы для неаутентифицированных пользователей, но избегать кэширования для аутентифицированных пользователей .
Я думал, что он всегда вернет HTTP-заголовок Vary:Cookie
, но это не так.
Выполняя тест с Fiddler и выполняя дважды один и тот же запрос, в первом HTTP-вызове все идет хорошо:
HTTP/1.1 200 OK
Cache-Control: public, max-age=300
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2012 10:53:36 GMT
Last-Modified: Thu, 09 Feb 2012 10:48:36 GMT
Vary: Cookie
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 09 Feb 2012 10:48:37 GMT
Content-Length: 441
Но во втором он перезаписывает заголовок:
HTTP/1.1 200 OK
Cache-Control: public, max-age=297
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2012 10:53:36 GMT
Last-Modified: Thu, 09 Feb 2012 10:48:36 GMT
Vary: *
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 09 Feb 2012 10:48:39 GMT
Content-Length: 441
Итак, насколько мне известно, браузеры не будут кэшировать запрос, даже если он общедоступен, поскольку Vary:*
означает, что запрос был сгенерирован с параметрами, которых нет ни в URL, ни в заголовках HTTP. Есть ли способ это исправить?
Привет.
UPDATE:
Аналогичным образом, когда я отправляю два идентичных аутентифицированных запроса, первый вызов получает модификатор private
, но не заголовок Vary
:
HTTP/1.1 200 OK
Cache-Control: private, max-age=300
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2012 12:43:14 GMT
Last-Modified: Thu, 09 Feb 2012 12:38:14 GMT
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 09 Feb 2012 12:38:14 GMT
Content-Length: 443
Но второй получает тот же ответ, что и запрос без аутентификации:
HTTP/1.1 200 OK
Cache-Control: public, max-age=298
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2012 12:44:32 GMT
Last-Modified: Thu, 09 Feb 2012 12:39:32 GMT
Vary: *
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 09 Feb 2012 12:39:33 GMT
Content-Length: 443
Я загрузил тестовый проект, показывающий проблему , так что, возможно, вы захотите попробовать.
Обратите внимание, что существует IHttpModule
, который устанавливает запрос как аутентифицированный или нет, в зависимости от того, есть ли у куки-файла запрос или нет, это не «реальный» подход, он только для целей тестирования.
Проект содержит только веб-страницу со ссылкой на себя, ссылкой для входа в систему и другой ссылкой для выхода из системы:
- Вход в систему: снова отправляет файл cookie в перенаправлении
HTTP 302
на домашнюю страницу.
- LogOut: снова отправляет файл cookie с истекшим сроком действия
HTTP 302
на домашнюю страницу.
ожидаемое / идеальное поведение будет:
- Пользователь получает доступ к индексу и получает страницу с сервера. На странице показывается дата "А".
- Пользователь снова получает доступ к индексу, и браузер показывает кешированную версию. На странице отображается дата «A».
- Очистить кеш браузера.
- Пользователь снова получает доступ к индексу, и браузер показывает кешированную версию сервера. На странице показывается дата «А».
- Пользователь нажимает кнопку входа, и брат получает новую страницу, на которой отображается дата "B".
- Пользователь нажимает кнопку выхода, и браузер получает страницу с кэшированным сервером. На странице снова появится дата «А».
Но это поведение до сих пор:
- Пользователь получает доступ к индексу и получает страницу с сервера. На странице показывается дата "А".
- Пользователь снова получает доступ к индексу, и браузер показывает кэшированную версию. На странице отображается дата «A».
- Очистить кеш браузера.
- Пользователь снова получает доступ к индексу, и браузер показывает кешированную версию сервера. На странице показывается дата «А».
- Пользователь нажимает кнопку входа, и брат получает новую страницу, на которой отображается дата «B».
- Пользователь нажимает кнопку выхода из системы, и браузер должен получить кэшированную страницу сервера, но не . На странице снова отображается дата «B» из кеша браузера. Это связано с тем, что в аутентифицированном ответе отсутствует заголовок
Vary
.
Я не знаю, если я ошибаюсь в кешировании, просто пропускаю некоторые детали или OutputCache
работает не очень хорошо, но я был бы признателен за любые рекомендации.
Приветствие.
ОБНОВЛЕНИЕ 2:
Мое намерение состоит в том, чтобы использовать семантику кэша HTTP для:
- Разрешить браузерам и прокси-серверам кэшировать "публичную" версию страницы.
- Разрешить браузерам кэшировать "аутентифицированную" версию страницы для своего пользователя.
Если я изменю объявление OutputCache для выполнения кэширования только на сервере и предотвращения кэширования в нисходящем и клиентском режимах:
[OutputCache(Duration=60*5, Location=OutputCacheLocation.Server, VaryByCustom="index")]
он ведет себя так, как ожидалось, но нисходящий и клиентский кеш запрещен, и это не то, что я хочу.