web-dev-qa-db-ja.com

IIS 7は200ではなく304を返します

IIS 7.で奇妙な問題があります。
時々、200ではなく304を返すようです。

Fiddlerでキャプチャされたリクエストの例を次に示します。
(リクエストされたファイルはまだブラウザのキャッシュにありません。)

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

リクエストにIf-Modified-SinceまたはIf-None-Matchがないことに注意してください。
しかし、それでも応答は次のとおりです。

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

誰かがここで間違っている可能性のある手がかりを持っていますか?

Windows Web Server 2008 R2でIIS 7を実行しています。

編集:

回避策を見つけました。キャッシュを有効にしてから、拡張レベルで無効にするとうまくいきました。

<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>
10
Ola Herrdahl

HTTP1.1仕様のセクション14.9 によると、Cache-Controlヘッダーのno-cacheディレクティブは、オリジンサーバー、つまりIISはリクエストのヘッダーを無視しています。

キャッシュ制御ディレクティブは、次の一般的なカテゴリに分類できます。

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

オリジンサーバーによって。

セクション14.9.1は、publicprivate、およびno-cacheを、キャッシュ可能なものを制限するディレクティブとして定義します。これは、サーバーによってのみ課されることができます。

.jsファイルをキャッシュしたくない場合は、アプリでno-cacheディレクティブを設定する(つまり、ASP.NETコード)か、使用するリクエストのCache-Controlヘッダーを変更する必要があります。 no-storeではなくno-cacheディレクティブ。

編集:
あなたのコメントに基づいて-はい、ファイルをキャッシュしたくないと思いました。 304は、ファイルがIISの内部キャッシュの1つにあるために発生する可能性があります。これらを見てください:

3
squillman

このバグも発生していましたが、アセット管理ライブラリ(カセット)を使用していました。この問題を詳細に調査した結果、この問題の根本的な原因はASP.NET、IIS、およびカセットの組み合わせにあることがわかりました。これがyourの問題かどうかはわかりません(Headers APIではなくCache APIを使用)。パターンは同じようです。

バグ#1

カセットは、gzip/deflateでコンテンツをエンコードできるため、Vary: Accept-Encodingヘッダーをバンドルへの応答の一部として設定します。

ただし、ASP.NET出力キャッシュは常に最初にキャッシュされた応答を常に返します。たとえば、最初のリクエストにAccept-Encoding: gzipがあり、カセットがgzip圧縮されたコンテンツを返す場合、ASP.NET出力キャッシュはURLをContent-Encoding: gzipとしてキャッシュします。同じURLへの次のリクエストで、受け入れ可能なエンコーディングが異なる(例:Accept-Encoding: deflate)と、Content-Encoding: gzipでキャッシュされた応答が返されます。

このバグは、カセットがHttpResponseBase.Cache AP​​Iを使用して出力キャッシュの設定(Cache-Control: publicなど)を設定し、HttpResponseBase.Headers AP​​Iを使用してVary: Accept-Encodingヘッダーを設定したことが原因です。問題は、ASP.NETのOutputCacheModulenot応答ヘッダーを認識しないことです。 Cache APIを介してのみ機能します。つまり、開発者が標準のHTTPだけでなく、目に見えない密結合APIを使用することを期待しています。

バグ#2

IIS 7.5(Windows Server 2008 R2))を使用する場合、バグ#1はIISカーネルお​​よびユーザーキャッシュで別の問題を引き起こす可能性があります。たとえば、バンドルはContent-Encoding: gzipで正常にキャッシュされ、IISカーネルキャッシュでnetsh http show cachestateで確認できます。200のステータスコードとコンテンツエンコーディング " gzip "。次のリクエストの受け入れ可能なエンコードが異なる場合(例:Accept-Encoding: deflateおよびバンドルのと一致するIf-None-Matchヘッダーハッシュの場合、IISのカーネルお​​よびユーザーモードキャッシュへの要求はmissと見なされ、304を返すカセットによって要求が処理されます。

ただし、IISのカーネルモードとユーザーモードが応答を処理すると、URLの応答が変更されたことがわかり、キャッシュを更新する必要があります。 IISカーネルキャッシュがnetsh http show cachestateで再度チェックされると、キャッシュされた200応答は304応答で置き換えられます。Accept-Encodingに関係なく、バンドルへの後続のすべての要求はIf-None-Matchは304応答を返します。予期しないAccept-EncodingIf-None-Matchのあるランダムリクエストが原因で、すべてのユーザーにコアスクリプトの304が提供されたこのバグの壊滅的な影響がわかりました。 。

問題は、IISカーネルお​​よびユーザーモードのキャッシュがAccept-Encodingヘッダーに基づいて変更できないことです。これの証拠として、Cache APIを回避策とともに使用することにより、以下では、IISカーネルお​​よびユーザーモードキャッシュは常にスキップされるようです(ASP.NET出力キャッシュのみが使用されます)。これは、netsh http show cachestateがASP.NETはIISワーカーと直接通信して、要求ごとにIISカーネルお​​よびユーザーモードキャッシュを選択的に有効または無効にします。

IIS(例:IIS Express 10))の新しいバージョンでこのバグを再現することはできませんでしたが、バグ#1は再現可能でした。

このバグに対する最初の修正は、IISカーネル/ユーザーモードキャッシングを他の言及したようなカセットリクエストに対してのみ無効にすることでした。これにより、前に追加のキャッシングレイヤーをデプロイするときにバグ#1を発見しました。クエリ文字列ハックが機能したのは、OutputCacheModule APIがCacheに基づいて変化するために使用されていない場合、 QueryStringはキャッシュミスを記録するためですリクエストにQueryString がある場合。

Workaround

私たちはとにかくカセットから離れることを計画していたので、カセットのフォークを維持する(またはPRをマージしようとする)のではなく、この問題を回避するためにHTTPモジュールを使用することを選びました。

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

    }
}

これが誰かに役立つことを願っています????!

1
TheCloudlessSky

しばらく同じ問題が発生し、すべてのキャッシュがオフになっています...しかし、IIS7の圧縮モジュールをインストールしたところ、デフォルトで既存のサイトで静的ファイルの圧縮が有効になりました。影響を受けたサイトのすべての圧縮をオフにしたところ、現在は正常に動作しているようですtouch wood

1
Hobietje