web-dev-qa-db-ja.com

ASP.NETMVCおよびIEキャッシング-応答ヘッダーの操作は無効

バックグラウンド

過去6か月間問題になっていない問題を同僚がデバッグできるように支援しようとしています。 ASP.NET MVC 2アプリケーションの最新の展開後、開いたり保存したりするためにユーザーにPDFファイルを強制するFileResult応答は、 PDFリーダーがそれらを開くためのクライアントマシン。

影響を受けるブラウザは、以前のバージョンのIE(特に6)のみです。FirefoxとChromeおよび新しいバージョンのIE( > 8)すべてが期待どおりに動作することを念頭に置いて、次のセクションでは、問題を再現するために必要なアクションを定義します。

動作

  1. ユーザーがアクションメソッドを指すリンク(href属性を持つプレーンハイパーリンク)をクリックします。
  2. アクションメソッドは、バイトストリームとして表されるPDFを生成します。メソッド常にはPDFを再作成します。
  3. Actionメソッドでは、応答をキャッシュする方法をブラウザーに指示するためにヘッダーが設定されます。彼らです:

    response.AddHeader("Cache-Control", "public, must-revalidate, post-check=0, pre-check=0");
    response.AddHeader("Pragma", "no-cache");
    response.AddHeader("Expires", "0");
    

    headers が何をするのか正確によく知らない人のために:

    a。 Cache-Control:public

    通常はキャッシュ不可または非共有キャッシュ内でのみキャッシュ可能である場合でも、応答が任意のキャッシュによってキャッシュされる可能性があることを示します。

    b。 Cache-Control:must-revalidate

    キャッシュによって受信された応答にmust-revalidateディレクティブが存在する場合、そのキャッシュは、最初にOriginサーバーで再検証せずに、後続の要求に応答するために古くなった後、エントリを使用してはなりません。

    c。 Cache-Control:pre-check(IE5で導入)

    エンティティの鮮度をチェックする必要があるまでの間隔を秒単位で定義します。このチェックは、ユーザーにリソースが表示された後に実行される場合がありますが、次のラウンドトリップでキャッシュされたコピーが最新であることを確認します。

    d。 Cache-Control:post-check(IE5で導入)

    ユーザーにリソースを表示する前に、エンティティの鮮度をチェックする必要がある間隔を秒単位で定義します。

    e。 プラグマ:no-cache(HTTP/1.0との下位互換性を確保するため)

    No-cacheディレクティブが要求メッセージに存在する場合、アプリケーションは、要求されているもののキャッシュされたコピーがある場合でも、要求をOriginサーバーに転送する必要があります。

    f。 有効期限

    Expiresエンティティヘッダーフィールドは、応答が古くなったと見なされるまでの日付/時刻を示します。

  4. アクションからファイルを返します

    return File(file, "mime/type", fileName);
    
  5. ユーザーには、[開く/保存]ダイアログボックスが表示されます

  6. [保存]をクリックすると期待どおりに機能しますが、[開く]をクリックするとPDFリーダーが起動しますが、保存されている一時ファイルIEはすでに削除されています。リーダーがファイルを開こうとすると、ファイルが見つからないと文句を言います(そしてそうです)。

ここには、同じヘッダーを使用してExcel、CSV、PDF、Word、およびその他の大量のコンテンツをユーザーに強制するアプリが6つあり、問題は発生していません。

質問

  • ヘッダーは私たちがやろうとしていることに対して正しいですか?ファイルを一時的に存在させたい(キャッシュする)が、要求が同一であっても常に新しいバージョンに置き換えられるようにしたい

応答ヘッダーは、FileResultを返す前にactionメソッドで設定されます。同僚に、FileResultから継承する新しいクラスを作成してみて、代わりにExecuteResultメソッドをオーバーライドして、ヘッダーを変更してからbase.ExecuteResult()を実行するように依頼しました。 -そのステータスはありません。

「0」の「Expires」ヘッダーが原因であるという予感があります。 このW3Cの記事 によると、「0」に設定すると「すでに期限切れ」になります。期限切れにしたいのですが、IEを処理するアプリケーションがファイルシステムを開く前に、ファイルシステムから削除したくないだけです。

いつものように、ありがとう!

編集:ソリューション

さらにテストすると(Fiddlerを使用してヘッダーを検査)、設定されていると思われる応答ヘッダーがブラウザーによって解釈されているものではないことがわかりました。私自身はコードに精通していなかったので、根本的な問題に気づいていませんでした。ヘッダーがアクションメソッドの外部で踏みにじられていました。

それでも、私はこの質問を開いたままにしておきます。まだ目立っているのはこれです。0の値を持つExpiresヘッダーと-1の間にいくつかの不一致があるようです。誰かが違いを主張できるなら設計上、IEに関して、それでも私はそれについて聞きたいです。ただし、解決策として、上記のヘッダーは、すべてのブラウザーでExpires値を-1に設定すると意図したとおりに機能します。

アップデート1

投稿 すべてのブラウザでWebページのキャッシュを制御する方法は? Expires = 0に設定すると、すべてのブラウザでキャッシュを防ぐことができると詳細に説明されています。この0vsではまだ販売されていません。 -1引数.。

24
Cᴏʀʏ

私はあなたがただ使うべきだと思います

_HttpContext.Current.Response.Cache.SetMaxAge (new TimeSpan (0));
_

または

_HttpContext.Current.Response.Headers.Set ("Cache-Control", "private, max-age=0");
_

_max-age=0_を設定します。これは、キャッシュの再検証以外の意味はありません( ここ を参照)。データからのハッシュのカスタムチェックサムを使用してヘッダーにETagを追加で設定する場合は、前のリクエストのETagがサーバーに送信されます。サーバーはデータを返すか、データが以前とまったく同じである場合は、空の本文とステータスコードとして_HttpStatusCode.NotModified_を返すことができます。 Webブラウザがローカルブラウザのキャッシュからデータを取得する場合。

_Cache-Control: private_を使用することをお勧めします。これにより、2つの重要なことが強制されます。1)プロキシでのデータのキャッシュをオフにします。これには、非常に積極的なキャッシュ設定が含まれる場合があります。2)データのキャッシュは許可されますが、共有は許可されません。他のユーザーとのキャッシュの。あるユーザーに返すデータを別のユーザーが読み取ることができないため、プライバシーの問題を解決できます。ちなみに、コードHttpContext.Current.Response.Cache.SetMaxAge (new TimeSpan (0))はデフォルトでHTTPヘッダーに_Cache-Control: private, max-age=0_を設定します。 _Cache-Control: public_を使用したい場合は、SetCacheability (HttpCacheability.Public);を使用して動作を上書きするか、_Headers.Set_の代わりに_Cache.SetMaxAge_を使用できます。

HTTPプロトコルのより多くのキャッシュオプションを研究することに興味がある場合は、 キャッシュチュートリアル を読むことをお勧めします。

[〜#〜]更新[〜#〜]:自分の立場を明確にするために、さらに情報を書くことにしました。 Wikipediaの 情報 に対応します。Mosaic2.7、Netscape 2.0、Internet Explorer 3.0などの古いWebブラウザは、RFC2068で説明されているHTTP/1.1の先行標準である1996年3月をサポートしています。古いWebブラウザが_max-age=0_ HTTPヘッダーをサポートしていることをテストしないでください。いずれにせよ、Netscape2.06とInternetExplorer4.0はHTTP1.1を確実にサポートしています。

したがって、最初に質問する必要があります。使用するHTML標準はどれですか。 1997年1月に公開された最新のHTML3.2の代わりにHTML2.0をまだ使用していますか? 1997年12月に公開された少なくともHTML4.0を使用していると思います。したがって、少なくともHTML 4.0でアプリケーションを構築すると、HTTP 1.1をサポートするWebクライアントをサイトに向け、Webクライアントを無視(サポートしない)することができます。 HTTP1.1をサポートしていません。

次に、他の「Cache-Control」ヘッダーについて「private、max-age = 0」として説明します。私の意見では、ヘッダーを含めることは純粋なパラノイアです。自分でキャッシュの問題があるので、他の別のヘッダーも含めようとしましたが、後でRFC2616のセクション14.9を注意深く読んだ後、「Cache-Control:private、max-age = 0」のみを使用します。

追加で説明できる唯一の「Cache-Control」ヘッダーは、前に参照したセクション14.9.4で説明されている「must-revalidate」です。ここに引用があります:

特定のプロトコル機能の信頼性の高い操作をサポートするには、must-revalidateディレクティブが必要です。すべての状況で、HTTP /1.1キャッシュはmust-revalidateディレクティブに従わなければなりません。特に、キャッシュが何らかの理由でオリジンサーバーに到達できない場合、504(ゲートウェイタイムアウト)応答を生成する必要があります。

サーバーは、エンティティに対する要求の再検証に失敗すると、サイレントに実行されない金融取引などの誤った操作が発生する可能性がある場合にのみ、再検証が必要なディレクティブを送信する必要があります。受信者は、このディレクティブに違反する自動化されたアクションを実行してはならず、再検証が失敗した場合にエンティティの未検証のコピーを自動的に提供してはなりません。

これは推奨されませんが、厳しい接続制約の下で動作するユーザーエージェントは、このディレクティブに違反する可能性がありますが、違反する場合は、未検証の応答が提供されたことをユーザーに明示的に警告する必要があります。警告は、検証されていないアクセスごとに提供する必要があり、明示的なユーザー確認を要求する必要があります。

インターネット接続に問題がある場合、「ゲートウェイタイムアウト」メッセージのある空のページが表示されることがあります。これは、「must-revalidate」ディレクティブの使用法に由来します。 「ゲートウェイタイムアウト」メッセージがユーザーに本当に役立つとは思いません。

したがって、上司への呼び出しで「ビジー」信号が聞こえた場合に自己破壊的な手順を開始することを好む人は、「Cache-Control」ヘッダーで「must-revalidate」ディレクティブを追加で使用する必要があります。私がお勧めする他の人は、「Cache-Control:private、max-age = 0」だけを使用することをお勧めします。

16
Oleg

これが遅いことは知っていますが、このリンクは、このトピックに関心のあるすべての人にとって大きな助けになる可能性があります: http://dotnet.dzone.com/articles/output-caching-aspnet-mvc

2
Rosdi Kasim

IEの場合、Expires: -1を設定する必要があったことを覚えています。 Internet Explorerでのキャッシュを防ぐ方法 次のコードスニペットでこれを確認しているようです。

<% Response.CacheControl = "no-cache" %>
<% Response.AddHeader "Pragma", "no-cache" %>
<% Response.Expires = -1 %>

コードを振り返ると、これが私が見つけたものです。また、Cache-Control: privateを設定すると、SSLで正しく動作しない可能性があることを漠然と覚えています。

Response.AddHeader("Cache-Control", "no-cache");
Response.AddHeader("Expires", "-1");

また、 つまり、キャッシュしたくないのですか?-1について言及していますが、代わりにResponse.Cacheのメソッドを使用しています。

// Stop Caching in IE
Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
// Stop Caching in Firefox
Response.Cache.SetNoStore();

ただし、 ASPページキャッシュの問題(IE8) は、このコードが機能しないことを示しています。

0
Kevin Hakanson