IIS 7 restituisce 304 anziché 200


10

Ho uno strano problema con IIS 7.
A volte sembra restituire un 304 anziché un 200.

Ecco una richiesta di esempio catturata con Fiddler:
(Nota che il file richiesto non si trova ancora nella cache del mio browser.)

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

Si noti che nella richiesta non sono presenti corrispondenze If-Modified-Since o If-None.
Ma la risposta è ancora:

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

Qualcuno ha la minima idea di cosa potrebbe esserci di sbagliato qui?

Sto eseguendo IIS 7 su Windows Web Server 2008 R2.

MODIFICARE:

Ho trovato una soluzione alternativa, abilitare la memorizzazione nella cache e quindi disabilitarlo a livello di estensione ha fatto il trucco per me.

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

Sto riscontrando lo stesso problema EXACT e sta causando molti problemi su un server Web molto occupato. IIS restituisce un 304, anche se il client non ha ancora una copia della risorsa.
Philippe Leybaert,

@Philippe, hai già trovato una soluzione? Altrimenti vedi la mia modifica sopra per una soluzione alternativa e controlla la nuova risposta di seguito.
Ola Herrdahl,

@OlaHerrdahl, la tua soluzione è perfetta :) Ho avuto anche questo problema esatto. Grazie!
Ardee Aram,

Risposte:


3

Secondo la sezione 14.9 della specifica HTTP1.1 , la no-cachedirettiva per l'intestazione Cache-Control è imposibile solo dal server di origine, il che significa che IIS ignora l'intestazione nella richiesta.

Le direttive di controllo della cache possono essere suddivise in queste categorie generali:

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

dal server di origine.

La Sezione 14.9.1 definisce public, privatee no-cachecome le direttive che limitano ciò che è memorizzabile nella cache, che può essere imposta solo dal server.

Se non desideri che il tuo file .js venga memorizzato nella cache, dovrai impostare la no-cachedirettiva nell'app (ad es. Il codice ASP.NET) o dovrai cambiare l' Cache-Controlintestazione nella richiesta per usare la no-storedirettiva invece di no-cache.

EDIT: in
base al tuo commento - sì, ho pensato che non volessi che il file fosse memorizzato nella cache. Il 304, quindi, potrebbe arrivare come risultato del file in una delle cache interne di IIS. Dai un'occhiata a questi:


Penso che tu abbia frainteso il mio problema qui. Il file non si trova ancora nella mia cache. Ma il server risponde ancora con un 304 ... Questo sembra accadere casualmente durante la navigazione del sito in tutti i principali browser.
Ola Herrdahl,

@Ola Herrdahl: dai un'occhiata alla mia modifica.
squillman

Ho provato a disabilitare la memorizzazione nella cache anche in IIS e non fa differenza ... :(
Ola Herrdahl

1

Ho avuto lo stesso problema per un po 'e ho disattivato tutta la cache ... Tuttavia, ho installato il modulo di compressione per IIS7 ad un certo punto che per impostazione predefinita aveva abilitato la compressione di file statici sui miei siti esistenti. Ho disattivato tutta la compressione per i siti interessati e ora sembrano funzionare con un tocco di legno .


1

Stavamo riscontrando anche questo errore ma stavamo usando una libreria di gestione patrimoniale (Cassette). Dopo un'indagine approfondita di questo problema, abbiamo scoperto che la causa principale di questo problema è con una combinazione di ASP.NET, IIS e Cassette. Non sono sicuro che questo sia il tuo problema (utilizzando l' HeadersAPI anziché l' CacheAPI), ma il modello sembra essere lo stesso.

Bug n. 1

Cassette imposta l' Vary: Accept-Encodingintestazione come parte della sua risposta a un bundle poiché può codificare il contenuto con gzip / deflate:

Tuttavia, la cache di output ASP.NET restituirà sempre la risposta memorizzata per prima. Ad esempio, se la prima richiesta ha Accept-Encoding: gzipe Cassette restituisce contenuto compresso con gzip, la cache di output ASP.NET memorizzerà nella cache l'URL come Content-Encoding: gzip. La richiesta successiva allo stesso URL ma con una codifica accettabile diversa (ad es. Accept-Encoding: deflate) Restituirà la risposta memorizzata nella cache con Content-Encoding: gzip.

Questo errore è causato da Cassette che utilizza l' HttpResponseBase.CacheAPI per impostare le impostazioni della cache di output (ad es. Cache-Control: public) Ma che utilizza l' HttpResponseBase.HeadersAPI per impostare l' Vary: Accept-Encodingintestazione. Il problema è che ASP.NET nonOutputCacheModule è a conoscenza delle intestazioni di risposta; funziona solo tramite l' CacheAPI. Cioè, si aspetta che lo sviluppatore utilizzi un'API invisibilmente accoppiata anziché solo HTTP standard.

Bug n. 2

Quando si utilizza IIS 7.5 (Windows Server 2008 R2), il bug n. 1 può causare un problema separato con il kernel IIS e le cache degli utenti. Ad esempio, una volta che un bundle viene correttamente memorizzato nella cache Content-Encoding: gzip, è possibile vederlo nella cache del kernel IIS con netsh http show cachestate. Mostra una risposta con 200 codici di stato e codifica del contenuto di "gzip". Se la richiesta successiva ha una codifica differente accettabile (ad esempio Accept-Encoding: deflate) e un If-None-Matchun'intestazione che corrisponda hash del fascio, la richiesta in modalità kernel e utente cache di IIS sarà considerato un perdere . Pertanto, facendo sì che la richiesta venga gestita da Cassette che restituisce un 304:

Tuttavia, una volta che il kernel di IIS e le modalità utente elaborano la risposta, vedranno che la risposta per l'URL è cambiata e la cache deve essere aggiornata. Se la cache del kernel IIS viene netsh http show cachestatenuovamente verificata , la risposta 200 memorizzata nella cache viene sostituita con una risposta 304. Tutte le successive richieste al bundle, indipendentemente da Accept-Encodinge If-None-Matchrestituiranno una risposta 304. Abbiamo visto gli effetti devastanti di questo bug in cui a tutti gli utenti è stato fornito un 304 per il nostro script principale a causa di una richiesta casuale che ha avuto un imprevisto Accept-Encodinge If-None-Match.

Il problema sembra essere che il kernel IIS e le cache in modalità utente non sono in grado di variare in base all'intestazione Accept-Encoding. A riprova di ciò, usando l' CacheAPI con la soluzione seguente, il kernel IIS e le cache in modalità utente sembrano essere sempre ignorate (viene utilizzata solo la cache di output ASP.NET). Ciò può essere confermato controllando che netsh http show cachestatesia vuoto con la soluzione alternativa di seguito. ASP.NET comunica direttamente con il lavoratore IIS per abilitare o disabilitare selettivamente il kernel IIS e le cache in modalità utente per richiesta.

Non è stato possibile riprodurre questo errore nelle versioni più recenti di IIS (ad esempio IIS Express 10). Tuttavia, il bug n. 1 era ancora riproducibile.

La nostra correzione originale per questo bug era disabilitare la cache in modalità utente / kernel IIS solo per richieste Cassette come altre citate. In questo modo, abbiamo scoperto il bug n. 1 durante la distribuzione di un ulteriore livello di cache davanti ai nostri server web. Il motivo per cui l'hacking della stringa di query ha funzionato è perché OutputCacheModuleregistrerà un errore nella cache se l' CacheAPI non è stata utilizzata per variare in base al QueryString e se la richiesta ha unQueryString .

Soluzione

Abbiamo comunque pianificato di allontanarci da Cassette, quindi piuttosto che mantenere il nostro fork di Cassette (o cercare di unire le PR), abbiamo deciso di utilizzare un modulo HTTP per aggirare questo 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()
    {

    }
}

Spero che questo aiuti qualcuno 😄!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.