У меня есть метод действий, который я хочу кэшировать:
[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 или нет, это не подход "реальной жизни", он просто предназначен для тестирования.
Проект содержит только веб-страницу со ссылкой на себя, ссылку, в которую вы входите, и другую ссылку, в которой вы выходите:
- LogIn: снова перенаправляет файл cookie в перенаправление
HTTP 302
на домашнюю страницу. - LogOut: снова отправляет файл cookie с истекшим сроком в
HTTP 302
на главную страницу.
ожидаемое/идеальное поведение:
- Индекс доступа пользователей и получить страницу с сервера. Дата показа страницы "A" .
- Индекс доступа пользователей снова, и браузер показывает кешированную версию. На странице отображается дата "A" .
- Очистить кеш браузера.
- Индекс доступа пользователей снова, и браузер отображает версию кеширования сервера. Дата показа страницы "A" .
- Пользователь нажимает логин, а broswer получает новую страницу, отображающую дату "B" .
- Пользователь нажимает кнопку выхода из системы, и браузер получает страницу кэширования сервера. На странице появится дата "A" .
Но это поведение до сих пор:
- Индекс доступа пользователей и получить страницу с сервера. Дата показа страницы "A" .
- Индекс доступа пользователей снова, и браузер показывает кешированную версию. На странице отображается дата "A" .
- Очистить кеш браузера.
- Индекс доступа пользователей снова, и браузер отображает версию кеширования сервера. Дата показа страницы "A" .
- Пользователь нажимает логин, а broswer получает новую страницу, отображающую дату "B" .
- Пользователь нажимает кнопку выхода из системы, а браузер должен получать серверную кешированную страницу, но не. Страница show date "B" снова из кеша браузера. Это связано с отсутствием заголовка
Vary
в аутентифицированном ответе.
Я не знаю, что-то не так в кэшировании, просто не хватает деталей или OutputCache
работает не очень хорошо, но я был бы признателен за любые рекомендации.
Приветствия.
ОБНОВЛЕНИЕ 2:
Я намерен использовать семантику кеша HTTP для:
- Разрешить браузерам и прокси кэшировать "общедоступную" версию страницы.
- Разрешить браузерам кэшировать "аутентифицированную" версию страницы для своего пользователя.
Если я изменил объявление OutputCache, чтобы сделать кеширование только на сервере и предотвратить кэширование ниже по течению и клиенту:
[OutputCache(Duration=60*5, Location=OutputCacheLocation.Server, VaryByCustom="index")]
он ведет себя так, как ожидалось, но кеш-сервер и клиентский кеш предотвращаются, и это не то, что я хочу.