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