IIS 7 devuelve 304 en lugar de 200

10

Tengo un problema extraño con IIS 7.
A veces parece devolver un 304 en lugar de un 200.

Aquí hay una solicitud de muestra capturada con Fiddler:
(Tenga en cuenta que el archivo solicitado aún no se encuentra en el caché de mi navegador).

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: ...

Tenga en cuenta que no hay If-Modified-Since o If-None-Match en la solicitud.
Pero aún así la respuesta es:

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

¿Alguien tiene idea de lo que podría estar mal aquí?

Estoy ejecutando IIS 7 en Windows Web Server 2008 R2.

EDITAR:

He encontrado una solución alternativa, habilitar el almacenamiento en caché y luego deshabilitarlo en un nivel de extensión fue el truco para mí.

<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>
Ola Herrdahl
fuente
Tengo el mismo problema EXACTAMENTE y está causando muchos problemas en un servidor web muy ocupado. IIS devuelve un 304, a pesar de que el cliente aún no tiene una copia del recurso.
Philippe Leybaert
@Philippe, ¿ya has encontrado una solución? De lo contrario, vea mi edición anterior para una solución alternativa y consulte la nueva respuesta a continuación.
Ola Herrdahl
@OlaHerrdahl, su solución es perfecta :) También tuve este problema exacto. ¡Gracias!
Ardee Aram

Respuestas:

3

De acuerdo con la sección 14.9 de la especificación HTTP1.1 , la no-cachedirectiva para el encabezado Cache-Control solo es imposible para el servidor de origen, lo que significa que IIS está ignorando el encabezado en su solicitud.

Las directivas de control de caché se pueden dividir en estas categorías generales:

  - Restrictions on what are cacheable; these may only be imposed

por el servidor de origen.

La Sección 14.9.1 define public, privatey no-cachecomo las directivas que restringen lo que se puede almacenar en caché, que solo puede imponer el servidor.

Si no desea que su archivo .js se almacene en caché, deberá configurar la no-cachedirectiva en la aplicación (es decir, el código ASP.NET) o deberá cambiar el Cache-Controlencabezado en la solicitud para usar la no-storedirectiva en lugar de no-cache.

EDITAR:
según su comentario, sí, supuse que no quería que el archivo se almacenara en caché. El 304, entonces, podría venir como resultado de que el archivo esté en una de las cachés internas de IIS. Echa un vistazo a estos:

squillman
fuente
Creo que entendiste mal mi problema aquí. El archivo aún no se encuentra en mi caché. Pero aún así el servidor responde con un 304 ... Esto parece suceder al azar cuando se navega por el sitio en todos los principales navegadores.
Ola Herrdahl
@Ola Herrdahl: Echa un vistazo a mi edición.
Squillman
También he intentado deshabilitar el almacenamiento en caché en IIS y no hay diferencia ... :(
Ola Herrdahl
1

He tenido el mismo problema durante un tiempo y he desactivado todo el almacenamiento en caché ... Sin embargo, instalé el módulo de compresión para IIS7 en algún momento que, de manera predeterminada, había habilitado la compresión de archivos estáticos en mis sitios existentes. Desactivé toda la compresión de los sitios afectados y ahora parece que están trabajando con madera fina .


fuente
1

También estábamos experimentando este error pero estábamos usando una biblioteca de administración de activos (Cassette). Después de una extensa investigación de este problema, descubrimos que la causa raíz de este problema es con una combinación de ASP.NET, IIS y Cassette. No estoy seguro de si este es su problema (usando la HeadersAPI en lugar de la CacheAPI), pero el patrón parece ser el mismo.

Bug # 1

Cassette establece el Vary: Accept-Encodingencabezado como parte de su respuesta a un paquete ya que puede codificar el contenido con gzip / deflate:

Sin embargo, el caché de salida de ASP.NET siempre devolverá la respuesta que se almacenó en caché primero. Por ejemplo, si la primera solicitud tiene Accept-Encoding: gzipy Cassette devuelve contenido comprimido, la caché de salida de ASP.NET almacenará en caché la URL como Content-Encoding: gzip. La siguiente solicitud a la misma URL pero con una codificación aceptable diferente (por ejemplo Accept-Encoding: deflate) devolverá la respuesta almacenada en caché Content-Encoding: gzip.

Este error se debe a que Cassette usa la HttpResponseBase.CacheAPI para establecer la configuración de caché de salida (por ejemplo Cache-Control: public) pero usa la HttpResponseBase.HeadersAPI para establecer el Vary: Accept-Encodingencabezado. El problema es que el ASP.NET OutputCacheModulees no consciente de las cabeceras de respuesta; solo funciona a través de la CacheAPI. Es decir, espera que el desarrollador use una API invisiblemente acoplada en lugar de solo HTTP estándar.

Bug # 2

Cuando se usa IIS 7.5 (Windows Server 2008 R2), el error n. ° 1 puede causar un problema separado con el kernel IIS y las memorias caché del usuario. Por ejemplo, una vez que un paquete se almacena en caché con éxito Content-Encoding: gzip, es posible verlo en el caché del kernel IIS con netsh http show cachestate. Muestra una respuesta con código de estado 200 y codificación de contenido de "gzip". Si la siguiente solicitud tiene una codificación aceptable diferente (p Accept-Encoding: deflate. Ej. ) Y un If-None-Matchencabezado que coincide con el hash del paquete, la solicitud en el kernel de IIS y las cachés de modo de usuario se considerarán como incorrectas . Por lo tanto, haciendo que Cassette maneje la solicitud, que devuelve un 304:

Sin embargo, una vez que el kernel y los modos de usuario de IIS procesen la respuesta, verán que la respuesta para la URL ha cambiado y la caché debe actualizarse. Si se netsh http show cachestatevuelve a verificar el caché del kernel IIS , la respuesta 200 en caché se reemplaza por una respuesta 304. Todas las solicitudes posteriores al paquete, independientemente de Accept-Encodingy If-None-Matchdevolverán una respuesta 304. Vimos los efectos devastadores de este error donde todos los usuarios recibieron un 304 para nuestro script central debido a una solicitud aleatoria que tuvo un inesperado Accept-Encodingy If-None-Match.

El problema parece ser que el caché de IIS y las memorias caché de modo de usuario no pueden variar según el Accept-Encodingencabezado. Como prueba de esto, al usar la CacheAPI con la solución a continuación, las memorias caché del núcleo IIS y del modo de usuario parecen omitirse siempre (solo se usa la memoria caché de salida ASP.NET). Esto se puede confirmar comprobando que netsh http show cachestateestá vacío con la solución a continuación. ASP.NET se comunica con el trabajador de IIS directamente para habilitar o deshabilitar selectivamente el kernel de IIS y las cachés en modo de usuario por solicitud.

No pudimos reproducir este error en versiones más nuevas de IIS (por ejemplo, IIS Express 10). Sin embargo, el error # 1 todavía era reproducible.

Nuestra solución original para este error fue deshabilitar el almacenamiento en caché del modo IIS del kernel / usuario solo para solicitudes de Cassette como se mencionó anteriormente. Al hacerlo, descubrimos el error n. ° 1 al implementar una capa adicional de almacenamiento en caché frente a nuestros servidores web. La razón por la que funcionó el hack de cadena de consulta es porque OutputCacheModuleregistrará un error de caché si la CacheAPI no se ha utilizado para variar en función de QueryString y si la solicitud tiene unQueryString .

Solución alterna

De todos modos, hemos planeado alejarnos de Cassette, por lo que en lugar de mantener nuestra propia bifurcación de Cassette (o tratar de fusionar un PR), optamos por usar un módulo HTTP para solucionar este problema.

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()
    {

    }
}

Espero que esto ayude a alguien 😄!

TheCloudlessSky
fuente