IIS 7 gibt 304 statt 200 zurück

10

Ich habe ein seltsames Problem mit IIS 7.
Manchmal scheint es eine 304 anstelle einer 200 zurückzugeben.

Hier ist eine Beispielanforderung, die mit Fiddler erfasst wurde:
(Beachten Sie, dass sich die angeforderte Datei noch nicht im Cache meines Browsers befindet.)

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

Beachten Sie, dass die Anforderung kein If-Modified-Since oder If-None-Match enthält.
Trotzdem lautet die Antwort:

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

Hat jemand eine Ahnung, was hier falsch sein könnte?

Ich verwende IIS 7 unter Windows Web Server 2008 R2.

BEARBEITEN:

Ich habe eine Problemumgehung gefunden, das Caching aktiviert und dann auf Erweiterungsebene deaktiviert. Das hat den Trick für mich getan.

<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
quelle
Ich habe genau das gleiche Problem und es verursacht viele Probleme auf einem sehr ausgelasteten Webserver. IIS gibt einen 304 zurück, obwohl der Client noch keine Kopie der Ressource hat.
Philippe Leybaert
@Philippe, hast du schon eine Lösung gefunden? Andernfalls finden Sie eine Problemumgehung in meiner obigen Bearbeitung und lesen Sie die neue Antwort unten.
Ola Herrdahl
@OlaHerrdahl, deine Problemumgehung ist perfekt :) Ich hatte auch genau dieses Problem. Vielen Dank!
Ardee Aram

Antworten:

3

Gemäß Abschnitt 14.9 der HTTP1.1-Spezifikation kann die no-cacheDirektive für den Cache-Control-Header nur vom Ursprungsserver festgelegt werden. Dies bedeutet, dass IIS den Header in Ihrer Anforderung ignoriert.

Die Cache-Steueranweisungen können in diese allgemeinen Kategorien unterteilt werden:

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

vom Ursprungsserver.

Abschnitt 14.9.1 definiert public, privateund no-cachewie in den Richtlinien zu beschränken , was zwischenspeicherbar ist, die nur durch den Server gestellt werden.

Wenn Sie nicht möchten, dass Ihre .js-Datei zwischengespeichert wird, müssen Sie entweder die no-cacheDirektive in der App festlegen (dh den ASP.NET-Code) oder den Cache-ControlHeader in der Anforderung ändern , um die no-storeDirektive zu verwenden statt no-cache.

EDIT:
Basierend auf Ihrem Kommentar - ja, ich nahm an, dass Sie nicht wollten, dass die Datei zwischengespeichert wird. Der 304 könnte dann als Ergebnis der Datei in einem der internen Caches von IIS kommen. Schauen Sie sich diese an:

Squillman
quelle
Ich denke, Sie haben mein Problem hier falsch verstanden. Die Datei befindet sich noch nicht in meinem Cache. Trotzdem antwortet der Server mit einem 304 ... Dies scheint zufällig zu passieren, wenn die Site in allen gängigen Browsern durchsucht wird.
Ola Herrdahl
@Ola Herrdahl: Schau dir meine Bearbeitung an.
Squillman
Ich habe versucht, das Caching auch in IIS zu deaktivieren, und es macht keinen Unterschied ... :(
Ola Herrdahl
1

Ich habe seit einiger Zeit das gleiche Problem und habe das gesamte Caching deaktiviert ... Ich habe jedoch irgendwann das Komprimierungsmodul für IIS7 installiert, das standardmäßig die Komprimierung statischer Dateien auf meinen vorhandenen Sites aktiviert hatte. Ich habe die Komprimierung für die betroffenen Stellen deaktiviert und jetzt scheinen sie feines Holz zu bearbeiten .


quelle
1

Dieser Fehler trat ebenfalls auf, wir verwendeten jedoch eine Asset Management-Bibliothek (Kassette). Nach einer umfassenden Untersuchung dieses Problems haben wir festgestellt, dass die Hauptursache für dieses Problem in einer Kombination aus ASP.NET, IIS und Kassette liegt. Ich bin nicht sicher, ob dies Ihr Problem ist (Verwendung der HeadersAPI anstelle der CacheAPI), aber das Muster scheint dasselbe zu sein.

Fehler Nr. 1

Cassette setzt den Vary: Accept-EncodingHeader als Teil seiner Antwort auf ein Bundle, da er den Inhalt mit gzip / deflate codieren kann:

Der ASP.NET-Ausgabecache gibt jedoch immer die Antwort zurück, die zuerst zwischengespeichert wurde. Wenn beispielsweise die erste Anforderung hat Accept-Encoding: gzipund Kassette komprimierten Inhalt zurückgibt, speichert der ASP.NET-Ausgabecache die URL als Content-Encoding: gzip. Die nächste Anforderung an dieselbe URL, jedoch mit einer anderen akzeptablen Codierung (z. B. Accept-Encoding: deflate), gibt die zwischengespeicherte Antwort mit zurück Content-Encoding: gzip.

Dieser Fehler wird dadurch verursacht, dass Cassette die HttpResponseBase.CacheAPI verwendet, um die Einstellungen für den Ausgabecache festzulegen (z. B. Cache-Control: public), aber die HttpResponseBase.HeadersAPI verwendet, um den Vary: Accept-EncodingHeader festzulegen. Das Problem ist , dass die ASP.NET OutputCacheModuleist nicht bewusst , Response - Header; Es funktioniert nur über die CacheAPI. Das heißt, es wird erwartet, dass der Entwickler eine unsichtbar eng gekoppelte API verwendet und nicht nur Standard-HTTP.

Fehler # 2

Bei Verwendung von IIS 7.5 (Windows Server 2008 R2) kann Fehler 1 ein separates Problem mit dem IIS-Kernel und den Benutzercaches verursachen. Wenn ein Bundle beispielsweise erfolgreich zwischengespeichert wurde Content-Encoding: gzip, kann es im IIS-Kernel-Cache mit angezeigt werden netsh http show cachestate. Es zeigt eine Antwort mit 200 Statuscode und Inhaltscodierung von "gzip". Wenn die nächste Anforderung eine andere akzeptable Codierung (z. B. Accept-Encoding: deflate) und einen If-None-MatchHeader hat, der mit dem Hash des Bundles übereinstimmt, wird die Anforderung in den Kernel- und Benutzermodus-Caches von IIS als Fehlschlag betrachtet . Dadurch wird die Anforderung von der Kassette verarbeitet, die eine 304 zurückgibt:

Sobald jedoch der Kernel- und der Benutzermodus von IIS die Antwort verarbeiten, sehen sie, dass sich die Antwort für die URL geändert hat und der Cache aktualisiert werden sollte. Wenn der IIS-Kernel-Cache netsh http show cachestateerneut überprüft wird, wird die zwischengespeicherte 200-Antwort durch eine 304-Antwort ersetzt. Alle nachfolgenden Anforderungen an das Bundle, unabhängig von Accept-Encodingund If-None-Matchgeben eine 304-Antwort zurück. Wir haben die verheerenden Auswirkungen dieses Fehlers gesehen, bei dem allen Benutzern aufgrund einer zufälligen Anfrage mit einem unerwarteten Accept-Encodingund ein 304 für unser Kernskript zugestellt wurde If-None-Match.

Das Problem scheint zu sein, dass der Cache des IIS-Kernels und des Benutzermodus je nach Accept-EncodingHeader nicht variieren kann . Als Beweis dafür Cachescheinen bei Verwendung der API mit der folgenden Problemumgehung die IIS-Kernel- und Benutzermodus-Caches immer übersprungen zu werden (nur der ASP.NET-Ausgabecache wird verwendet). Dies kann bestätigt werden, indem überprüft wird, ob netsh http show cachestatedie folgende Problemumgehung leer ist. ASP.NET kommuniziert direkt mit dem IIS-Worker, um den Cache des IIS-Kernels und des Benutzermodus pro Anforderung selektiv zu aktivieren oder zu deaktivieren.

Wir konnten diesen Fehler auf neueren Versionen von IIS (z. B. IIS Express 10) nicht reproduzieren. Fehler Nr. 1 war jedoch immer noch reproduzierbar.

Unsere ursprüngliche Lösung für diesen Fehler bestand darin, das Zwischenspeichern des IIS-Kernels / Benutzermodus nur für Kassettenanforderungen zu deaktivieren, wie andere erwähnt haben. Auf diese Weise haben wir Fehler Nr. 1 beim Bereitstellen einer zusätzlichen Caching-Ebene vor unseren Webservern entdeckt. Der Grund, warum der Abfragezeichenfolgen-Hack funktioniert hat, ist, dass der OutputCacheModuleeinen Cache-Fehler aufzeichnet, wenn die CacheAPI nicht verwendet wurde, um basierend auf dem zu variieren, QueryString und wenn die Anforderung eine hatQueryString .

Problemumgehung

Wir hatten sowieso vor, uns von der Kassette zu entfernen. Anstatt unsere eigene Kassettengabel beizubehalten (oder zu versuchen, eine PR zusammenzuführen), haben wir uns für die Verwendung eines HTTP-Moduls entschieden, um dieses Problem zu umgehen.

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

    }
}

Ich hoffe das hilft jemandem 😄!

TheCloudlessSky
quelle