【ASP.NET MVC】CSSやJavaScriptを更新したときにキャッシュさせない

Web アプリを開発していると、改修を行ったのに画面の画像が古いまま、等という経験があると思います。

現場によってはユーザーに画面のキャッシュをクリアしてくださいと、案内を出しているケースもあるかもしれません。

今回の記事では、CSS やJavaScript を更新した際に、キャッシュさせず画面に反映させる方法をご紹介します。

キャッシュについて

キャッシュとは

キャッシュとは、一時的にデータを保存して高速なアクセスを可能にする仕組みです。

ユーザーがWeb ページにアクセスする際に、そのデータをローカルのキャッシュメモリやハードディスクに保存します。

それにより、次回同じデータにアクセスする際には、サーバーに再度リクエストせずローカルからデータを利用します。これによりネットワークトラフィックを削減し、応答時間を短縮させることができます。

キャッシュはWeb のパフォーマンス向上やネットワークの効率化に役立つ重要な仕組みであり、多くのWeb サイトやアプリケーションで広く利用されています。

キャッシュによる影響

改修を行ったのに画面の画像や一部処理が更新されない原因にはキャッシュが影響しています。

キャッシュしたデータを表示し応答時間を短縮させている反面、Web ページが更新されていた場合には古い情報を表示をしてしまうことがあります。

最新のWeb ページを表示させる方法

最も簡単な方法は、ユーザーのブラウザでキャッシュをクリアしてもらうことだと思います。

ブラウザの閲覧履歴を削除してもらう、改修を行ったWeb ページでスーパーリロードを行ってもらう等があります。

ただ、社内システムでユーザーが限られている場合等を除き、すべてのユーザーにこれらの操作を行ってもらうのは現実的ではなく、ユーザビリティもよくありません。

サーバー側で常に最新のWeb 画面を表示させるのが良いと思われます。

その方法の一つとしてCache Busting があります。

Cache Busting とは

Cache Busting とは、Web 開発においてキャッシュされたリソースの更新や再取得を促すための手法です。

一般的な方法としては、リソースのURL にクエリパラメーターを追加する方法があります。

クエリパラメーターを付与することにより、ブラウザーはリソースのURL が変更されたと判断し、キャッシュを無視して新しいバージョンのリソースを取得します。

クエリパラメーターを付与するWeb アプリを作る

更新を行ったCSS やJavaScript ファイルの参照URL にクエリパラメーターを付与させる処理を作成してみます。

参照URL 一つずつにクエリパラメータを手入力するのは手間がかかるため、Bundle を利用しまとめてクエリパラメーターを付与します。

Bundle とは

バンドルでは、複数のファイルを単一のファイルに連結します。

バンドルを使用すると、Web ページなどの Web 資産のレンダリングに必要なサーバー要求の数を減らすことができます。

learn.microsoft.com

開発環境

今回使用した環境は下記になります。

項目 内容
IDE Microsoft Visual Studio Enterprise 2017
フレームワーク .NET Framework 4.6.1
ASP.NET MVC Framework
言語 C#
Webサーバ IIS

実装サンプル

各ファイルの概要は下記になります。

ファイル名 概要
BundleConfig.cs バンドル処理
_Layout.cshtml 共通レイアウト
sample.css 自作CSS
BundleConfig.cs

バンドルするファイルの参照URL にファイル更新日時をクエリパラメーターとして追加します。

更新をしたファイルはクエリパラメーターが更新されるため、キャッシュされません。

using System.IO;
using System.Web.Hosting;
using System.Web.Optimization;

namespace WebApplication6
{
    public class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
            // バンドルするCSSを指定
            bundles.Add(new ScriptBundle("~/bundles/sample").Include(
                      "~/Content/sample.css"
                ).AddLastModifiedQueryParam());
        }
    }

    /// <summary>
    /// バンドル拡張クラス
    /// </summary>
    public static class BundleExtensions
    {
        /// <summary>
        /// クエリパラメーター追加
        /// </summary>
        /// <param name="bd"></param>
        /// <returns></returns>
        public static Bundle AddLastModifiedQueryParam(this Bundle bd)
        {
            bd.Transforms.Add(new FileVersionBundleTransForm());
            return bd;
        }

        /// <summary>
        /// バンドル変換クラス(ファイルバージョン)
        /// </summary>
        public class FileVersionBundleTransForm : IBundleTransform
        {
            /// <summary>
            /// バンドル変換
            /// </summary>
            /// <param name="context"></param>
            /// <param name="response"></param>
            public void Process(BundleContext context, BundleResponse response)
            {
                foreach (var file in response.Files)
                {
                    string version =
                        File.GetLastWriteTime(HostingEnvironment
                        .MapPath(file.IncludedVirtualPath)).ToString("yyyyMMddHHmmss");

                    file.IncludedVirtualPath =
                        string.Concat(file.IncludedVirtualPath, "?v=", version);
                }
            }
        }
    }
}
sample.css

更新するCSS のサンプルです。

.sample {
    text-align:center;
}
_Layout.cshtml

Web 画面のサンプルです。

更新するCSS を含むバンドルを参照します。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - マイ ASP.NET アプリケーション</title>
    @Styles.Render("~/bundles/sample")
</head>
<body>
    <div class="sample">
        <img src="~/Content/Logo_JBS_TECH_BLOG.png" alt="test" />
    </div>

    @RenderBody()
</body>
</html>

実行結果

開発者ツールでCSS の参照URLを確認します。

クエリパラメーターにファイル更新日時が追加されています。

実行結果
実行結果

おわりに

CSS やJavaScript のキャッシュ対策は意外と忘れやすいと思います。

この記事が参考になれば幸いです。

執筆担当者プロフィール
石橋 侑樹

石橋 侑樹(日本ビジネスシステムズ株式会社)

これまで業務システムやWebアプリの開発、業務自動化等に携わってきました。サッカーが好きで休日は試合を見ていることが多いです。

担当記事一覧