42

最近、Last-Modified ヘッダーに出会いました。

  • MVC にどのように、どこに含めることができますか?
  • それを含めることの利点は何ですか?

静的ページとデータベース クエリについても、最後に変更されたヘッダーを mvc プロジェクトに含める方法の例が必要ですか?

はいの場合、どのようにoutputcacheとは異なりますか?

基本的に、ユーザーがキャッシュを更新したりクリアしたりする必要なく、ブラウザーがキャッシュをクリアして最新のデータまたはページを自動的に表示するようにしたいと考えています。

4

5 に答える 5

50

Last-Modified主にキャッシングに使用されます。変更時間を追跡できるリソースに対して返送されます。リソースはファイルである必要はありません。たとえば、UpdatedAt列がある dB 情報から生成されたページです。

各ブラウザーがリクエストで送信するヘッダーと組み合わせて使用​​されIf-Modified-Sinceます (以前にヘッダーを受信した場合Last-Modified)。

MVC にどのように、どこに含めることができますか?

Response.AddHeader

それを含めることの利点は何ですか?

動的に生成されるページのきめの細かいキャッシュを有効にします (たとえば、DB フィールドUpdatedAtを最終変更ヘッダーとして使用できます)。

すべてを機能させるには、次のようにする必要があります。

public class YourController : Controller
{
    public ActionResult MyPage(string id)
    {
        var entity = _db.Get(id);
        var headerValue = Request.Headers["If-Modified-Since"];
        if (headerValue != null)
        {
            var modifiedSince = DateTime.Parse(headerValue).ToLocalTime();
            if (modifiedSince >= entity.UpdatedAt)
            {
                return new HttpStatusCodeResult(304, "Page has not been modified");
            }
        }

        // page has been changed.
        // generate a view ...

        // .. and set last modified in the date format specified in the HTTP rfc.
        Response.AddHeader("Last-Modified", entity.UpdatedAt.ToUniversalTime().ToString("R"));
    }
}

DateTime.Parse で形式を指定する必要がある場合があります。

参考文献:

免責事項: ASP.NET/MVC3 があなたが管理するものをサポートしているかどうかはわかりませんLast-Modified

アップデート

拡張メソッドを作成できます。

public static class CacheExtensions
{
    public static bool IsModified(this Controller controller, DateTime updatedAt)
    {
        var headerValue = controller.Request.Headers['If-Modified-Since'];
        if (headerValue != null)
        {
            var modifiedSince = DateTime.Parse(headerValue).ToLocalTime();
            if (modifiedSince >= updatedAt)
            {
                return false;
            }
        }

        return true;
    }

    public static ActionResult NotModified(this Controller controller)
    {
        return new HttpStatusCodeResult(304, "Page has not been modified");
    }   
}

そして、次のように使用します。

public class YourController : Controller
{
    public ActionResult MyPage(string id)
    {
        var entity = _db.Get(id);
        if (!this.IsModified(entity.UpdatedAt))
            return this.NotModified();

        // page has been changed.
        // generate a view ...

        // .. and set last modified in the date format specified in the HTTP rfc.
        Response.AddHeader("Last-Modified", entity.UpdatedAt.ToUniversalTime().ToString("R"));
    }
}
于 2012-05-11T05:38:48.150 に答える
19


更新:私の新しい答えをチェックしてください


MVC にどのように、どこに含めることができますか?

ビルトインOutputCacheフィルターがその役割を果たし、それらのヘッダーをキャッシュに使用します。asまたはを設定すると、OuputCacheフィルタはLast-Modifiedヘッダーを使用します。LocationClientServerAndClient

[OutputCache(Duration = 60, Location = "Client")]
public ViewResult PleaseCacheMe()
{
    return View();
}

それを含めることの利点は何ですか?

条件付きキャッシュ フラッシュによるクライアント側キャッシュの活用

静的ページとデータベース クエリについても、最後に変更されたヘッダーを mvc プロジェクトに含める方法の例が必要ですか?

このリンクには、サンプルを試すのに十分な情報が含まれています。html のような静的ページの場合、画像 IIS はLast-Modifiedヘッダーの設定/チェックを行い、ファイルの最終更新日を使用します。データベース クエリの場合は、SqlDependencyでを設定できますOutputCache

はいの場合、どのように出力キャッシュが異なりますか? Last-Modified ヘッダーを含める必要があるのはいつですか? また、いつ outputcache を使用する必要がありますか?

OutputCacheASP.NET MVC でキャッシュ メカニズムを実装するために使用されるアクション フィルターです。OutputCacheクライアント側キャッシング、サーバー側キャッシングなど、さまざまな方法でキャッシングを実行できます。Last-Modifiedヘッダーは、クライアント側でキャッシュを実現する 1 つの方法です。を asOutputCacheに設定すると、フィルターはそれを使用します。LocationClient

クライアント側のキャッシュ (Last-ModifiedまたはETag) を使用する場合、ブラウザーのキャッシュは後続の要求で自動的に更新されるため、F5 を実行する必要はありません。

于 2012-05-12T17:33:18.777 に答える
16

Last-Modified と OutputCache の比較

OutputCache属性は、IIS Web サーバーでの出力キャッシュを制御します。これは、ベンダー固有のサーバー機能です ( IIS 7 の出力キャッシュを構成する を参照してください)。また、このテクノロジの強力な機能に興味がある場合は、ASP.NET MVC3 でのキャッシュの調査を読むことをお勧めします。

Last-Modified応答ヘッダーとそれに対応するIf-Modified-Since要求ヘッダーは、検証キャッシュの概念 (セクションキャッシュ コントロール) を表しています。これらのヘッダーは HTTP プロトコルの一部であり、rfc4229で指定されています。

OutputCache と検証は排他的ではなく、組み合わせることができます。

どのようなキャッシング シナリオが私を満足させますか?

いつものように:場合によります。

100 ヒット/秒のページで 5 秒の OutputCache を構成すると、負荷が大幅に軽減されます。OutputCache を使用すると、500 件のヒットのうち 499 件をキャッシュから提供できます (データベース ラウンドトリップ、計算、レンダリングのコストはかかりません)。

めったに変更をすぐに提供する必要がない場合は、検証シナリオによって帯域幅を大幅に節約できます。特に、無駄のない 304 ステータス メッセージと比較して大きなコンテンツを提供する場合。ただし、すべてのリクエストがソースの変更を検証するため、変更はすぐに採用されます。

Last-Modified 属性の実装サンプル

私の経験に基づいて、検証シナリオ (最終更新日) をアクション フィルター属性として実装することをお勧めします。(ところで:これ、属性として実装された他のキャッシング シナリオです)

ファイルからの静的コンテンツ

[LastModifiedCache]
public ActionResult Static()
{
    return File("c:\data\static.html", "text/html");
}

動的コンテンツのサンプル

[LastModifiedCache]
public ActionResult Dynamic(int dynamicId)
{
    // get data from your backend (db, cache ...)
    var model = new DynamicModel{
        Id = dynamivId,
        LastModifiedDate = DateTime.Today
    };
    return View(model);
}

public interface ILastModifiedDate
{
    DateTime LastModifiedDate { get; }
}

public class DynamicModel : ILastModifiedDate
{
    public DateTime LastModifiedDate { get; set; }
}

LastModifiedCache 属性

public class LastModifiedCacheAttribute : ActionFilterAttribute 
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is FilePathResult)
        {
            // static content is served from file in my example
            // the last file write time is taken as modification date
            var result = (FilePathResult) filterContext.Result;
            DateTime lastModify = new FileInfo(result.FileName).LastWriteTime;
            
            if (!HasModification(filterContext.RequestContext, lastModify))
                filterContext.Result = NotModified(filterContext.RequestContext, lastModify);
            SetLastModifiedDate(filterContext.RequestContext, lastModify);
        }

        if (filterContext.Controller.ViewData.Model is HomeController.ILastModifiedDate)
        {
            // dynamic content assumes the ILastModifiedDate interface to be implemented in the model
            var modifyInterface = (HomeController.ILastModifiedDate)filterContext.Controller.ViewData.Model;
            DateTime lastModify = modifyInterface.LastModifiedDate;

            if (!HasModification(filterContext.RequestContext, lastModify))
                filterContext.Result = NotModified(filterContext.RequestContext, lastModify);
            filterContext.RequestContext.HttpContext.Response.Cache.SetLastModified(lastModify);
        }

        base.OnActionExecuted(filterContext);
    }

    private static void SetLastModifiedDate(RequestContext requestContext, DateTime modificationDate)
    {
        requestContext.HttpContext.Response.Cache.SetLastModified(modificationDate);
    }

    private static bool HasModification(RequestContext context, DateTime modificationDate)
    {
        var headerValue = context.HttpContext.Request.Headers["If-Modified-Since"];
        if (headerValue == null)
            return true;

        var modifiedSince = DateTime.Parse(headerValue).ToLocalTime();
        return modifiedSince < modificationDate;
    }

    private static ActionResult NotModified(RequestContext response, DateTime lastModificationDate)
    {
        response.HttpContext.Response.Cache.SetLastModified(lastModificationDate);
        return new HttpStatusCodeResult(304, "Page has not been modified");
    }
}

グローバル LastModified サポートを有効にする方法

LastModifiedCache 属性を global.asax.cs の RegisterGlobalFilters セクションに追加して、mvc プロジェクトでこのタイプのキャッシュをグローバルに有効にすることができます。

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    ...
    filters.Add(new LastModifiedCacheAttribute());
    ...
}
于 2012-10-30T22:24:10.820 に答える
1

これは、キャッシングとOutputCache.

最初に 2 番目の質問にお答えします。

それを含めることの利点は何ですか?

ブラウザは、サーバーから返された応答をキャッシュします。キャッシングは主に 3 つのヘッダーによって制御Cache-ControlLast-ModifiedExpiresますETag

Last-Modifiedヘッダーは、リソースが最後にいつ変更されたかをブラウザーに通知します。リソースは、静的ファイルまたは動的に作成されたビューのいずれかです。ブラウザがそのリソースのリクエストを行うときはいつでも、サーバーをチェックしますLast-Modified。私のキャッシュからの応答を喜んで使用します。それ以外の場合は、新しい応答をすぐに送信してください。" . (ブラウザは、Last-Modified以前にサーバーから返された値を、 という新しいヘッダーで渡すことに注意してくださいIf-Modified-Since)

理想的には、サーバーはIf-Modified-Sinceヘッダーから値を読み取り、現在の変更日を確認する必要があり、それらが同じ場合は304 (NOT MODIFIED)を返すか、現在の変更日を渡してリソースの新しいコピーを再度返す必要があります。Last-Modifiedヘッダー。

利点はブラウザのキャッシングです。ブラウザーのキャッシュを利用することで、サーバーは重複した応答の作成を回避できます。また、ブラウザーにキャッシュされた応答が古いように見える場合は、新しい応答を返すこともできます。最終的な目標は時間を節約することです。

MVC にどのように、どこに含めることができますか?

画像、html ファイルなどの静的リソースの場合、 IIS がそのジョブを処理するため、HowWhereの設定について心配する必要はありません。IIS は、ファイルの最終変更日をヘッダー値として使用します。Last-Modified

MVC アクションによって返される HTML コンテンツのような動的ページの場合、どのようにLast-Modifiedヘッダー値を決定できますか? 動的に駆動されるページはほとんどがデータ駆動型であり、以前に返された応答が古いかどうかを判断するのは私たちの責任です。

ブログがあり、記事の詳細を表示するページがあるとします (他の詳細は表示されません)。ページのバージョンは、最終更新日または作成日 (記事がまだ変更されていない場合) によって決定されます。論文。したがって、ビューを配信する対応するアクションで@jgauffin が回答したのと同じ作業を行う必要があります。

コントローラーのアクションごとに含める必要がありますか?というコメントで質問しました。

アクションからデータベースから最終変更日を読み取るロジックを抽象化できる場合は、アクション全体でコードが重複するのを回避しながら、アクション フィルターを使用してジョブを実行できます。問題は、アクションから詳細をどのように抽象化するかです。テーブル/列名を属性に渡すのが好きですか? あなたはそれを理解しなければなりません!

例として..

[LastModifiedCacheFilter(Table = "tblArticles", Column = "last_modified")]
public ViewResult Post(int postId)
{
   var post = ... get the post from database using the postId
   return View(post);
}

以下に示す実装の疑似コード (これはテストしていないことを意味します:) は、LastModifiedCacheFilterAttributeTable/Column を使用して最終更新日を読み取りますが、他の方法でもかまいません。アイデアはOnActionExecuting、チェックを実行して 304 を返すメソッド (キャッシュがまだ新しい場合) とOnResultExecuted、最新の変更日を読み取り/設定するメソッドにあります。

public class LastModifiedCacheFilterAttribute : ActionFilterAttribute
{
    // Could be some other things instead of Table/Column
    public string Table { get; set; }
    public string Column { get; set; }    

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
      // var lastModified = read the value from the passed Column/Table and set it here 

      var ifModifiedSinceHeader = filterContext.RequestContext.HttpContext.Request.Headers["If-Modified-Since"];

      if (!String.IsNullOrEmpty(ifModifiedSinceHeader))
      {
        var modifiedSince = DateTime.Parse(ifModifiedSinceHeader).ToLocalTime();
        if (modifiedSince >= lastModified)
        {
          filterContext.Result = new EmptyResult();
          filterContext.RequestContext.HttpContext.Response.Cache.SetLastModified(lastModified.ToUniversalTime());
          filterContext.RequestContext.HttpContext.Response.StatusCode = 304;
        }
      }

      base.OnActionExecuting(filterContext);
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
      // var lastModified = read the value from the passed Column/Table and set it herefilterContext.RequestContext.HttpContext.Response.Cache.SetLastModified(lastModified.ToUniversalTime());
      base.OnResultExecuted(filterContext);
    }
}

OutputCache 属性を使用できないのはなぜですか?

私の分析によると、OutputCache属性はLast-Modifiedキャッシュメカニズムを使用していません。もう 1 つは、古いページ キャッシング メカニズムを使用しているため、カスタマイズや拡張が困難なことです。

すべてのアクションに最終変更メカニズムを実装する必要は本当にありますか?

本当に必要ありません。そのような応答を作成するのに時間がかかり、応答がネットワークを下ってブラウザに到達するのに時間がかかる、最終変更メカニズムをアクションに実装できます。他のケースでは、すべてのアクションを実装するのは単なるオーバーヘッドであり、実装する前に利点を測定する必要があると感じています. もう 1 つの主なポイントは、多くの場合、ページのバージョンは1 つのテーブル列だけで決まるわけではなく、他の多くの要素によって決まる可能性があり、そのような場合、これを実装するのはより複雑になる可能性があるということです!

についてのポイントETag

質問はヘッダーに関するものですが、[回答を投稿] ボタンをクリックする前にLast-Modified何かを伝えておく必要があります。ヘッダー (日時に依存)と比較して、ヘッダー (ハッシュ値に依存) は、ブラウザーにキャッシュされた応答が最新かどうかを判断する際により正確ですが、実装が少し複雑になる可能性があります。IIS には、静的リソースのヘッダーと共にヘッダーも含まれています。このメカニズムを実装する前に、グーグルで検索して、役立つライブラリがあるかどうかを確認してください。ETagLast-ModifiedETagETagLast-Modified

于 2012-10-30T05:02:19.160 に答える