IIS 7 renvoie 304 au lieu de 200

10

J'ai un problème étrange avec IIS 7.
Parfois, il semble renvoyer un 304 au lieu d'un 200.

Voici un exemple de demande capturée avec Fiddler:
(Notez que le fichier demandé ne se trouve pas encore dans le cache de mon navigateur.)

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

Notez qu'il n'y a pas de correspondance If-Modified-Since ou If-None-Match dans la demande.
Mais la réponse est toujours:

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

Quelqu'un at-il une idée de ce qui pourrait mal se passer ici?

J'exécute IIS 7 sur Windows Web Server 2008 R2.

ÉDITER:

J'ai trouvé une solution de contournement, activer la mise en cache puis la désactiver au niveau d'une extension a fait l'affaire pour moi.

<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
la source
J'ai le même problème EXACT, et cela cause beaucoup de problèmes sur un serveur Web très occupé. IIS renvoie un 304, même si le client n'a pas encore de copie de la ressource.
Philippe Leybaert
@Philippe, avez-vous déjà trouvé une solution? Sinon, consultez ma modification ci-dessus pour une solution de contournement et consultez la nouvelle réponse ci-dessous.
Ola Herrdahl
@OlaHerrdahl, votre solution de contournement est parfaite :) J'ai également eu ce problème exact. Merci!
Ardee Aram

Réponses:

3

Selon la section 14.9 de la spécification HTTP1.1 , la no-cachedirective pour l'en-tête Cache-Control n'est imposable que par le serveur d'origine, ce qui signifie qu'IIS ignore l'en-tête dans votre demande.

Les directives de contrôle du cache peuvent être divisées en ces catégories générales:

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

par le serveur d'origine.

L' article 14.9.1 définit public, privateet no-cacheque les directives limitant ce qui est cacheable, qui ne peut être imposée par le serveur.

Si vous ne souhaitez pas que votre fichier .js soit mis en cache, vous devrez soit définir la no-cachedirective dans l'application (c'est-à-dire le code ASP.NET), soit changer l'en- Cache-Controltête de la demande pour utiliser la no-storedirective. au lieu de no-cache.

EDIT:
Sur la base de votre commentaire - oui, je suppose que vous ne vouliez pas que le fichier soit mis en cache. Le 304 peut alors provenir du fait que le fichier se trouve dans l'un des caches internes d'IIS. Jetez un oeil à ceux-ci:

squillman
la source
Je pense que vous avez mal compris mon problème ici. Le fichier ne se trouve pas encore dans mon cache. Mais le serveur répond toujours avec un 304 ... Cela semble se produire au hasard lors de la navigation sur le site dans tous les principaux navigateurs.
Ola Herrdahl
@Ola Herrdahl: Jetez un œil à mon montage.
squillman
J'ai également essayé de désactiver la mise en cache dans IIS et cela ne fait aucune différence ... :(
Ola Herrdahl
1

J'ai eu le même problème pendant un certain temps et la mise en cache a été désactivée ... Cependant, j'ai installé le module de compression pour IIS7 à un moment donné qui, par défaut, avait permis la compression de fichiers statiques sur mes sites existants. J'ai désactivé toute compression pour les sites impactés et maintenant ils semblent travailler le bois finement .


la source
1

Nous rencontrions également ce bogue, mais nous utilisions une bibliothèque de gestion des actifs (cassette). Après une enquête approfondie sur ce problème, nous avons constaté que la cause principale de ce problème est une combinaison d'ASP.NET, IIS et Cassette. Je ne suis pas sûr que ce soit votre problème (en utilisant l' HeadersAPI plutôt que l' CacheAPI), mais le modèle semble être le même.

Bug # 1

Cassette définit l'en- Vary: Accept-Encodingtête dans le cadre de sa réponse à un bundle car il peut encoder le contenu avec gzip / deflate:

Toutefois, le cache de sortie ASP.NET renvoie toujours la réponse qui a été mise en cache en premier. Par exemple, si la première demande a Accept-Encoding: gzipet que Cassette renvoie du contenu compressé, le cache de sortie ASP.NET mettra l'URL en cache Content-Encoding: gzip. La prochaine demande à la même URL mais avec un codage acceptable différent (par exemple Accept-Encoding: deflate) renverra la réponse mise en cache avec Content-Encoding: gzip.

Ce bogue est provoqué par Cassette utilisant l' HttpResponseBase.CacheAPI pour définir les paramètres de cache de sortie (par exemple Cache-Control: public) mais utilisant l' HttpResponseBase.HeadersAPI pour définir l'en- Vary: Accept-Encodingtête. Le problème est que ASP.NET OutputCacheModulen'est pas au courant des en-têtes de réponse; cela ne fonctionne que via l' CacheAPI. Autrement dit, il s'attend à ce que le développeur utilise une API étroitement couplée de manière invisible plutôt qu'un simple HTTP standard.

Bug # 2

Lors de l'utilisation d'IIS 7.5 (Windows Server 2008 R2), le bogue n ° 1 peut provoquer un problème distinct avec le noyau IIS et les caches utilisateur. Par exemple, une fois qu'un bundle est correctement mis en cache avec Content-Encoding: gzip, il est possible de le voir dans le cache du noyau IIS avec netsh http show cachestate. Il affiche une réponse avec 200 codes d'état et un encodage de contenu "gzip". Si la requête suivante a un codage différent acceptable (par exemple Accept-Encoding: deflate) et un en- If-None-Matchtête qui correspond au hachage du paquet, la demande dans le noyau de IIS et les caches mode utilisateur sera considéré comme un manque . Ainsi, le traitement de la demande par Cassette qui renvoie un 304:

Cependant, une fois que le noyau et les modes utilisateur d'IIS auront traité la réponse, ils verront que la réponse pour l'URL a changé et que le cache doit être mis à jour. Si le cache du noyau IIS est vérifié à netsh http show cachestatenouveau avec , la réponse 200 mise en cache est remplacée par une réponse 304. Toutes les demandes ultérieures au bundle, indépendamment de Accept-Encodinget If-None-Matchrenverront une réponse 304. Nous avons vu les effets dévastateurs de ce bogue où tous les utilisateurs ont reçu un 304 pour notre script principal en raison d'une demande aléatoire qui a eu un inattendu Accept-Encodinget If-None-Match.

Le problème semble être que le noyau IIS et les caches en mode utilisateur ne peuvent pas varier en fonction de l'en- Accept-Encodingtête. Pour preuve, en utilisant l' CacheAPI avec la solution de contournement ci-dessous, le noyau IIS et les caches en mode utilisateur semblent toujours être ignorés (seul le cache de sortie ASP.NET est utilisé). Cela peut être confirmé en vérifiant qu'il netsh http show cachestateest vide avec la solution de contournement ci-dessous. ASP.NET communique directement avec le travailleur IIS pour activer ou désactiver sélectivement le noyau IIS et les caches en mode utilisateur par demande.

Nous n'avons pas pu reproduire ce bogue sur les versions plus récentes d'IIS (par exemple IIS Express 10). Cependant, le bogue n ° 1 était toujours reproductible.

Notre correctif d'origine pour ce bogue était de désactiver la mise en cache du mode utilisateur / noyau IIS uniquement pour les demandes de cassette comme d'autres mentionnées. Ce faisant, nous avons découvert le bogue n ° 1 lors du déploiement d'une couche supplémentaire de mise en cache devant nos serveurs Web. La raison pour laquelle le hack de chaîne de requête a fonctionné est que l' OutputCacheModuleenregistrera un cache manquant si l' CacheAPI n'a pas été utilisée pour varier en fonction de QueryString et si la demande a unQueryString .

solution de contournement

Nous prévoyons de toute façon de nous éloigner de Cassette, donc plutôt que de maintenir notre propre fork de Cassette (ou d'essayer de fusionner un PR), nous avons choisi d'utiliser un module HTTP pour contourner ce problème.

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

    }
}

J'espère que cela aide quelqu'un 😄!

TheCloudlessSky
la source