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;
    }
}

Идея заключалась в том, чтобы сохранить кешированную версию страницы для неаутентифицированных пользователей, но избегайте кеширования для аутентифицированных .

Я думал, что он всегда будет возвращать 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. Есть ли способ исправить это?

С уважением.

ОБНОВЛЕНИЕ:

Аналогичным образом, когда я отправляю два идентичных аутентифицированных запроса, первый вызов получает модификатор 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 снова на главную страницу.
  • Выход: повторно отправляет просроченный файл cookie в HTTP 302 переадресации на домашнюю страницу.

Ожидаемое / идеальное поведение будет следующим:

  1. Индекс доступа пользователя и получение страницы с сервера. На странице отображается дата "А".
  2. Индекс доступа пользователей снова, и браузер показывает кешированную версию. На странице отображается дата "A".
  3. Очистить кеш браузера.
  4. Индекс доступа пользователей снова, и браузер показывает кешированную версию сервера. На странице отображается дата "А".
  5. Пользователь нажимает кнопку «Войти», и браузер получает новую страницу с датой «B».
  6. Пользователь нажимает кнопку выхода, и браузер получает кэшированную на сервере страницу. На странице снова отображается дата "А".

Но пока что это поведение:

  1. Индекс доступа пользователя и получение страницы с сервера. На странице отображается дата "А".
  2. Индекс доступа пользователей снова, и браузер показывает кешированную версию. На странице отображается дата "A".
  3. Очистить кеш браузера.
  4. Индекс доступа пользователей снова, и браузер показывает кешированную версию сервера. На странице отображается дата "А".
  5. Пользователь нажимает кнопку «Войти», и браузер получает новую страницу с датой «B».
  6. Пользователь нажимает кнопку выхода, и браузер должен получить кешированную страницу сервера, но не . На странице снова отображается дата "B" из кеша браузера. Это связано с отсутствием заголовка Vary в аутентифицированном ответе.

Я не знаю, ошибаюсь ли я в кешировании, просто упускаю какую-то деталь или OutputCache работает не очень хорошо, но я был бы признателен за любое руководство.

Ура.

ОБНОВЛЕНИЕ 2:

Я намерен использовать семантику кеширования HTTP, чтобы:

  1. Разрешить браузерам и прокси-серверам кэшировать «общедоступную» версию страницы.
  2. Разрешить браузерам кэшировать «аутентифицированную» версию страницы для своего пользователя.

Если я изменю объявление OutputCache, чтобы выполнять кэширование только на сервере и предотвращать кеширование нисходящего и клиентского каналов:

[OutputCache(Duration=60*5, Location=OutputCacheLocation.Server, VaryByCustom="index")]

он ведет себя так, как ожидалось, но предотвращается кеширование нисходящего потока и клиента, а это не то, что я хочу.

11
задан Community 23 May 2017 в 10:34
поделиться