ASP.NET Core MVCでCache-Controlを設定する

ASP.NET Advent Calendar 2016 - Qiitaの21日目の投稿となります。 テーマをガラッと変えました。

ASP.NET Core MVCのコントローラから返されるHTTPレスポンスヘッダのCache-Controlを設定してみます。

Cache-Control

Cache-Controlは、ブラウザ(やキャッシュサーバ)へキャッシュの利用有無や有効期限などの情報を提供する、HTTPヘッダです。 ブラウザの開発者モードで確認できます。

f:id:ohke:20161220212434p:plain:w250

詳しくはRFC7234を見てください。

ResponseCacheAttribute

ASP.NET CoreのCache-Controlでは、従前のOutputCacheAttibuteクラス(System.Web.Mvc)が使えず、代わりにResponseCacheAttibuteクラス(Microsoft.AspNetCore.Mvc)が提供されています。

キャッシュの有効化と無効化

まずはブラウザに30秒間キャッシュさせる方法を見てみましょう。

  • Durationパラメータにキャッシュする秒数を指定します。
[ResponseCache(Duration = 30)]
public IActionResult Index()
{
    return View();
}
  • max-ageにてキャッシュの有効期限が指定されます。
    • publicの詳細は後述。

f:id:ohke:20161220224449p:plain

次に、常に更新を確認し、更新が無い場合にはキャッシュを使う設定です。

  • Durationパラメータを0とする。
  • LocationパラメータをResponseCacheLocation.Noneとする。
[ResponseCache(Location = ResponseCacheLocation.None, Duration = 0)]
public IActionResult Index()
{
    return View();
}
  • max-age=0で、常に有効期限切れのキャッシュとなる。
  • no-cacheの有無による違いは無いはずですが、ブラウザの実装に依存します。 f:id:ohke:20161220224501p:plain

なお、更新の検知ではレスポンスヘッダのLast-Modified(最新更新日時)やETag(ファイルハッシュ値)が使われます。 次回以降のリクエストヘッダにIf-Modified-SinceLast-ModifiedIf-None-MatchETagの値が設定され、サーバ側で比較して更新があった(サーバ側の最新の値と一致しない)場合のみ新しいレスポンスを返します。

最後に、一切キャッシュさせない設定です。

  • NoStoreパラメータをtrueとする
[ResponseCache(NoStore = true)]
public IActionResult Index()
{
    return View();
}
  • no-storeでブラウザは常にサーバから再取得する(=一切キャッシュを使わない) f:id:ohke:20161220224513p:plain

Location

キャッシュ場所をLocationパラメータで設定します。

  • ResponseCacheLocation.None: no-store
  • ResponseCacheLocation.Client: private
    • クライアント(=ブラウザ)のみにキャッシュされる。
  • ResponseCacheLocation.Any: public
    • クライアントとキャッシュサーバ(=プロキシサーバなど)の両方でキャッシュされる。
[ResponseCache(Location = ResponseCacheLocation.Client, Duration = 120)]
public IActionResult Index()
{
    return View();
}
Cache-Control: private, max-age=120
Pragma: no-cache

CacheProfileName

コントローラのメソッドやクラスを跨いで使う設定については、名前を付けて参照することができます。

  • Startup#ConfigureServices内で下記のように設定します。
    • ここでは120秒でキャッシュする"Default"という名前の設定を追加。
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(options =>
        {
            options.CacheProfiles.Add("Default",
                new Microsoft.AspNetCore.Mvc.CacheProfile()
                {
                    Duration = 120
                });
        });
    }
}
  • コントローラクラスやメソッドにてCacheProfileNameパラメータで名前を指定する。
[ResponseCache(CacheProfileName = "Default")]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}

まとめ

ASP.NET CoreにてCache-Controlを制御する方法について調べてまとめてみました。

とはいえ、ブラウザの実装依存の部分も多々ありますので、ヘッダが正しく設定されていること、そして意図通りにキャッシュにアクセスされていることを開発者モードなどで確認することをおすすめします。