13

特定のページに、クライアント用に 10 分間、サーバー用に 24 時間のキャッシュを持たせたいと考えています。その理由は、ページが変更された場合、クライアントは 10 分以内に更新されたバージョンをフェッチしますが、何も変更されない場合、サーバーは 1 日に 1 回ページを再構築するだけで済みます。

問題は、出力キャッシュの設定がクライアントの設定を上書きしているように見えることです。これが私がセットアップしたものです:

カスタム ActionFilterAttribute クラス

public class ClientCacheAttribute : ActionFilterAttribute
{
    private bool _noClientCache;

    public int ExpireMinutes { get; set; }

    public ClientCacheAttribute(bool noClientCache) 
    {
        _noClientCache = noClientCache;
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        if (_noClientCache || ExpireMinutes <= 0)
        {
            filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
            filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
            filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
            filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            filterContext.HttpContext.Response.Cache.SetNoStore();
        }
        else
        {
            filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(ExpireMinutes));
        }

        base.OnResultExecuting(filterContext);
    }
}

ウェブ設定の設定

  <outputCacheSettings>
    <outputCacheProfiles>
      <add name="Cache24Hours" location="Server" duration="86400" varyByParam="none" />
    </outputCacheProfiles>
  </outputCacheSettings>

私はそれをどのように呼んでいますか:

[OutputCache(CacheProfile = "Cache24Hours")]
[ClientCacheAttribute(false, ExpireMinutes = 10)]
public class HomeController : Controller
{
  [...]
}

しかし、HTTP ヘッダーを見ると、次のように表示されます。

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Expires: -1

どうすればこれを適切に実装できますか? ASP.NET MVC 4 アプリケーションです。

4

3 に答える 3

8

サーバー側のキャッシュには独自のソリューションを実装する必要があり、クライアント側のキャッシュには ClientCacheAttribute または OutputCache を使用します。サーバー側キャッシュのカスタム ソリューションが必要な理由は次のとおりです。

  • ClientCacheAttributeは、HttpCachePolicyBase のタイプである Response.Cache にキャッシュ ポリシーを設定します。
  • また、組み込みのOutputCacheもキャッシュ ポリシーを Response.Cache に設定します。

ここで強調したいのは、we don't have collection of HttpCachePolicyBase but we only have one object of HttpCachePolicyBase so we can't set multiple cache policy for given response.

Http Cacheability を HttpCacheability.ServerAndPrivate に設定できたとしても、キャッシュ期間に関する他の問題が発生します (つまり、クライアント 10 分 & サーバー 24 時間)。

クライアント側のキャッシュにはOutputCacheを使用し、サーバー側のキャッシュには独自のキャッシュ メカニズムを実装することをお勧めします。

于 2013-02-19T13:06:46.993 に答える
4

OutputCache プロファイルで、場所を ServerAndClient に設定します。これを行うと、アクション フィルターが出力を適切に上書きするはずです。

于 2013-02-12T03:41:45.937 に答える
3

.Net 4.5 では、カスタム キャッシュ プロバイダーを作成しなくても、クライアントとサーバーのキャッシュ ポリシーを変えることができます。

// Set the cache response expiration to 3600 seconds (use your own value here).
HttpContext.Current.Response.Cache.SetExpires(DateTime.UtcNow.AddSeconds(3600));

// Set both server and browser caching.
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate);

// Prevent browser's default max-age=0 header on first request
// from invalidating the server cache on each request.
HttpContext.Current.Response.Cache.SetValidUntilExpires(true);

// Set an HTTP ETag header on the page using a random GUID.
HttpContext.Current.Response.Cache.SetETag(System.Guid.NewGuid()
                                           .ToString().Replace("-", ""));

// Set last modified time.
HttpContext.Current.Response.Cache.SetLastModified(DateTime.UtcNow);

// Now here is the critical piece that forces revalidation on each request!:
HttpContext.Current.Response.Cache.AppendCacheExtension(
    "must-revalidate, proxy-revalidate, max-age=0");

その結果、ページがサーバー キャッシュで再生成されるたびに、新しい ETag が取得されます。これにより、If-None-Match リクエストはページ全体をブラウザに返します。ブラウザーのキャッシュされたコピーがサーバー キャッシュで生成されたものと同じ (同じ ETag) である場合、ブラウザーは 304 Not Modified を返します。

AppendCacheExtension に追加したキャッシュ ヘッダーは、ネイティブ キャッシュによって出力されたヘッダーと競合しないことに注意してください。.Net キャッシュ自体によって発行されたキャッシュ ヘッダーを変更しようとすると、常に .Net が実行しようとしている内容に取って代わります。秘訣は、.Net が既に出力しているものを変更しようとするのではなく、競合しない新しいヘッダーを追加することです。最も重要なことは、max-age ヘッダーを追加する必要があることです。.SetMaxAge() は、サーバーにキャッシュされたページのコピーの最大経過時間も設定するため、使用しないでください。

これを理解するにはかなりの労力がかかりましたが、少なくとも.Net 4.5では機能します。

于 2014-06-17T17:05:02.153 に答える