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 😄!