У меня странная проблема с IIS 7.
Иногда кажется, что вместо 200 возвращается 304.
Вот пример запроса, записанного с помощью Fiddler:
(Обратите внимание, что запрошенный файл еще не находится в кеше моего браузера.)
GET https://[mysite]/Content/js/jquery.form.js HTTP/1.1 Accept: */* Referer: https://[mysite]/Welcome/News Accept-Language: sv-SE User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; OfficeLiveConnector.1.4; OfficeLivePatch.1.3; .NET4.0C; .NET4.0E) Accept-Encoding: gzip, deflate Host: [mysite] Connection: Keep-Alive Cache-Control: no-cache Cookie: ...
Обратите внимание, что в запросе нет If-Modified-Since или If-None-Match.
Но все же ответ:
HTTP/1.1 304 Not Modified Cache-Control: public Expires: Tue, 02 Mar 2010 06:26:08 GMT Last-Modified: Mon, 22 Feb 2010 21:58:44 GMT ETag: "1CAB40A337D4200" Server: Microsoft-IIS/7.5 X-Powered-By: ASP.NET Date: Mon, 01 Mar 2010 17:06:34 GMT
Кто-нибудь знает, что здесь может быть не так?
Я использую IIS 7 на Windows Web Server 2008 R2.
РЕДАКТИРОВАТЬ:
Я нашел обходной путь: включить кеширование, а затем отключить его на уровне расширения, помогло мне.
<configuration>
<system.webServer>
<caching enabled="true" enableKernelCache="true">
<profiles>
<add extension=".png" policy="DisableCache" kernelCachePolicy="DisableCache" />
<add extension=".gif" policy="DisableCache" kernelCachePolicy="DisableCache" />
<add extension=".js" policy="DisableCache" kernelCachePolicy="DisableCache" />
<add extension=".css" policy="DisableCache" kernelCachePolicy="DisableCache" />
</profiles>
</caching>
<staticContent>
<clientCache cacheControlMode="NoControl" />
</staticContent>
</system.webServer>
</configuration>
В соответствии с раздел 14.9 спецификации HTTP1.1, то no-cache
Директива для заголовка Cache-Control может быть введена только исходным сервером, что означает, что IIS игнорирует заголовок в вашем запросе.
Директивы управления кешем можно разбить на следующие общие категории:
- Restrictions on what are cacheable; these may only be imposed
исходным сервером.
Раздел 14.9.1 определяет public
, private
, и no-cache
как директивы, ограничивающие то, что кэшируется, что может быть наложено только сервером.
Если вы не хотите, чтобы ваш файл .js кэшировался, вам нужно либо установить no-cache
в приложении (например, код ASP.NET), или вам нужно будет изменить Cache-Control
заголовок в запросе на использование no-store
директива вместо no-cache
.
РЕДАКТИРОВАТЬ:
Основываясь на вашем комментарии - да, я предположил, что вы не хотите, чтобы файл кешировался. Следовательно, 304 может появиться в результате того, что файл находится в одном из внутренних кешей IIS. Взгляните на это:
У нас тоже была эта ошибка, но мы использовали библиотеку управления активами (Cassette). После тщательного расследования этой проблемы мы обнаружили, что основная причина этой проблемы связана с комбинацией ASP.NET, IIS и Cassette. Я не уверен, что это ваш проблема (использование Headers
API, а не Cache
API), но картина, похоже, такая же.
Кассета устанавливает Vary: Accept-Encoding
заголовок как часть ответа на пакет, поскольку он может кодировать содержимое с помощью gzip / deflate:
Однако кэш вывода ASP.NET всегда будет возвращать ответ, который был кэширован первым. Например, если в первом запросе Accept-Encoding: gzip
и Cassette возвращает сжатое содержимое, кэш вывода ASP.NET будет кэшировать URL как Content-Encoding: gzip
. Следующий запрос к тому же URL-адресу, но с другой допустимой кодировкой (например, Accept-Encoding: deflate
) вернет кешированный ответ с Content-Encoding: gzip
.
Эта ошибка вызвана тем, что кассета использует HttpResponseBase.Cache
API для настройки параметров кэша вывода (например, Cache-Control: public
) но используя HttpResponseBase.Headers
API для установки Vary: Accept-Encoding
заголовок. Проблема в том, что ASP.NET OutputCacheModule
является не осведомлены о заголовках ответов; он работает только через Cache
API. То есть он ожидает, что разработчик будет использовать невидимо тесно связанный API, а не просто стандартный HTTP.
При использовании IIS 7.5 (Windows Server 2008 R2) ошибка №1 может вызвать отдельную проблему с ядром IIS и пользовательскими кешами. Например, после успешного кэширования пакета с помощью Content-Encoding: gzip
, его можно увидеть в кеше ядра IIS с помощью netsh http show cachestate
. Он показывает ответ с кодом состояния 200 и кодировкой содержимого «gzip». Если следующий запрос имеет другую допустимую кодировку (например, Accept-Encoding: deflate
) и ан If-None-Match
заголовок, соответствующий хешу пакета, запрос в кеши ядра IIS и пользовательского режима будет считаться Мисс. Таким образом, запрос будет обработан Cassette, который возвращает 304:
Однако, как только ядро и пользовательский режим IIS обработают ответ, они увидят, что ответ для URL-адреса изменился и кеш должен быть обновлен. Если кеш ядра IIS проверяется с помощью netsh http show cachestate
снова кэшированный ответ 200 заменяется ответом 304. Все последующие запросы к пакету, независимо от Accept-Encoding
и If-None-Match
вернет ответ 304. Мы увидели разрушительные последствия этой ошибки, когда всем пользователям было предоставлено 304 для нашего основного скрипта из-за случайного запроса с неожиданным Accept-Encoding
и If-None-Match
.
Проблема, похоже, в том, что кеши ядра IIS и пользовательского режима не могут различаться в зависимости от Accept-Encoding
заголовок. В качестве доказательства этого, используя Cache
API с обходным путем ниже, кеши ядра IIS и пользовательского режима кажутся всегда пропускаемыми (используется только кеш вывода ASP.NET). Это можно подтвердить, проверив, что netsh http show cachestate
пусто с обходным путем ниже. ASP.NET напрямую взаимодействует с рабочим IIS, чтобы выборочно включать или отключать кеши ядра IIS и пользовательского режима для каждого запроса.
Нам не удалось воспроизвести эту ошибку в более новых версиях IIS (например, IIS Express 10). Однако ошибка №1 все еще воспроизводилась.
Нашим первоначальным исправлением этой ошибки было отключение кэширования в режиме ядра / пользователя IIS только для запросов Cassette, подобных другим, упомянутым. Таким образом, мы обнаружили ошибку №1 при развертывании дополнительного уровня кеширования перед нашими веб-серверами. Причина, по которой взлом строки запроса сработал, заключается в том, что OutputCacheModule
будет записывать промах кеша, если Cache
API не использовался для изменения в зависимости от QueryString
и если в запросе есть QueryString
.
Мы в любом случае планировали отказаться от Cassette, поэтому вместо того, чтобы поддерживать нашу собственную вилку Cassette (или пытаться объединить PR), мы решили использовать HTTP-модуль для решения этой проблемы.
public class FixCassetteContentEncodingOutputCacheBugModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PostRequestHandlerExecute += Context_PostRequestHandlerExecute;
}
private void Context_PostRequestHandlerExecute(object sender, EventArgs e)
{
var httpContext = HttpContext.Current;
if (httpContext == null)
{
return;
}
var request = httpContext.Request;
var response = httpContext.Response;
if (request.HttpMethod != "GET")
{
return;
}
var path = request.Path;
if (!path.StartsWith("/cassette.axd", StringComparison.InvariantCultureIgnoreCase))
{
return;
}
if (response.Headers["Vary"] == "Accept-Encoding")
{
httpContext.Response.Cache.VaryByHeaders.SetHeaders(new[] { "Accept-Encoding" });
}
}
public void Dispose()
{
}
}
Надеюсь, это кому-то поможет 😄!
У меня была такая же проблема какое-то время, и все кеширование отключено ... Однако в какой-то момент я установил модуль сжатия для IIS7, который по умолчанию включал сжатие статических файлов на моих существующих сайтах. Я отключил сжатие для затронутых сайтов, и теперь они, похоже, работают нормально постучать по дереву.