Deep-dive on the Next Gen Platform. Join the Webinar!

Skip Navigation
Show nav
Dev Center
  • Get Started
  • ドキュメント
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • ドキュメント
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
Hide categories

Categories

  • Heroku のアーキテクチャ
    • Dyno (アプリコンテナ)
      • Dyno Management
      • Dyno Concepts
      • Dyno Behavior
      • Dyno Reference
      • Dyno Troubleshooting
    • スタック (オペレーティングシステムイメージ)
    • ネットワーキングと DNS
    • プラットフォームポリシー
    • プラットフォームの原則
  • Developer Tools
    • コマンドライン
    • Heroku VS Code Extension
  • デプロイ
    • Git を使用したデプロイ
    • Docker によるデプロイ
    • デプロイ統合
  • 継続的デリバリーとインテグレーション
    • 継続的統合
  • 言語サポート
    • Node.js
      • Working with Node.js
      • Troubleshooting Node.js Apps
      • Node.js Behavior in Heroku
    • Ruby
      • Rails のサポート
      • Bundler の使用
      • Working with Ruby
      • Ruby Behavior in Heroku
      • Troubleshooting Ruby Apps
    • Python
      • Working with Python
      • Python でのバックグランドジョブ
      • Python Behavior in Heroku
      • Django の使用
    • Java
      • Java Behavior in Heroku
      • Working with Java
      • Maven の使用
      • Spring Boot の使用
      • Troubleshooting Java Apps
    • PHP
      • PHP Behavior in Heroku
      • Working with PHP
    • Go
      • Go の依存関係管理
    • Scala
    • Clojure
    • .NET
      • Working with .NET
  • データベースとデータ管理
    • Heroku Postgres
      • Postgres の基礎
      • Postgres スターターガイド
      • Postgres のパフォーマンス
      • Postgres のデータ転送と保持
      • Postgres の可用性
      • Postgres の特別なトピック
      • Migrating to Heroku Postgres
    • Heroku Data For Redis
    • Apache Kafka on Heroku
    • その他のデータストア
  • AI
    • Working with AI
  • モニタリングとメトリクス
    • ログ記録
  • アプリのパフォーマンス
  • アドオン
    • すべてのアドオン
  • 共同作業
  • セキュリティ
    • アプリのセキュリティ
    • ID と認証
      • シングルサインオン (SSO)
    • Private Space
      • インフラストラクチャネットワーキング
    • コンプライアンス
  • Heroku Enterprise
    • Enterprise Accounts
    • Enterprise Team
    • Heroku Connect (Salesforce 同期)
      • Heroku Connect の管理
      • Heroku Connect のリファレンス
      • Heroku Connect のトラブルシューティング
  • パターンとベストプラクティス
  • Heroku の拡張
    • Platform API
    • アプリの Webhook
    • Heroku Labs
    • アドオンのビルド
      • アドオン開発のタスク
      • アドオン API
      • アドオンのガイドラインと要件
    • CLI プラグインのビルド
    • 開発ビルドパック
    • Dev Center
  • アカウントと請求
  • トラブルシューティングとサポート
  • Salesforce とのインテグレーション
  • アプリのパフォーマンス
  • HTTP キャッシュヘッダーを使用したアプリケーションパフォーマンスの向上

HTTP キャッシュヘッダーを使用したアプリケーションパフォーマンスの向上

日本語 — Switch to English

最終更新日 2023年06月13日(火)

Table of Contents

  • 概要
  • HTTP キャッシュヘッダー
  • 条件付きリクエスト
  • 視認性
  • ユースケース
  • キャッシュの防止
  • 実装

現代の開発者は、アプリケーションパフォーマンスとエンドユーザーエクスペリエンスを向上させるために使用できるさまざまな手法やテクノロジを備えています。 最も見落とされがちなテクノロジの 1 つに HTTP キャッシュの技術があります。

HTTP キャッシングは、最新のすべての Web ブラウザにわたって汎用的に採用されている仕様であるため、Web アプリケーションでのその実装は簡単です。 これらの標準の適切な使用によりアプリケーションは大きなメリットが得られ、応答時間の改善やサーバー負荷の削減が実現されます。ただし、誤ったキャッシングのために、ユーザーに古いコンテンツが表示されたり、デバッグしにくい問題が発生したりする場合があります。この記事では、HTTP キャッシングと、HTTP キャッシュヘッダーベースの方式を採用すべきシナリオについて詳細に説明します。

概要

HTTP キャッシングは、ブラウザが Web リソースのローカルコピーを保存して、次にそのリソースが必要になったときにより高速に取得できるようにする場合に発生します。アプリケーションは、リソースを処理する場合、目的のキャッシュ動作を指定するキャッシュヘッダーをレスポンスにアタッチできます。

キャッシングなしのデフォルト

項目が完全にキャッシュされている場合、ブラウザは、サーバーにまったくアクセスせず、単に独自のキャッシュされたコピーを使用することを選択できます。

キャッシングありのデフォルト

たとえば、アプリケーションの CSS スタイルシートがブラウザによってダウンロードされた後、ユーザーのセッション中にそれを再びダウンロードする必要はありません。これは、JavaScript ファイル、画像、変更される頻度の低い動的コンテンツなどの多くのアセットタイプにも当てはまります。これらの場合、ユーザーのブラウザはこのファイルをローカルにキャッシュし、リソースが再度要求されるたびにそのコピーを使用すると有効です。 HTTP キャッシュヘッダーを使用しているアプリケーションは、このキャッシュ動作を制御し、サーバー側の負荷を軽減することができます。

直感的には、エンドユーザーのブラウザが HTTP キャッシュヘッダーの主要なコンシューマーであると考えられます。ただし、これらの HTTP キャッシュヘッダーは、ソースサーバーとエンドユーザーの間にあるすべての中間プロキシおよびキャッシュによって使用したり、処理したりできます。

HTTP キャッシュヘッダー

主なキャッシュヘッダーとして、Cache-Control​ と Expires​ の 2 つがあります。

Cache-Control

Cache-Control ヘッダーが設定されていないと、他のどのキャッシュヘッダーでも結果は生成されません。

Cache-Control​ ヘッダーは、ブラウザでのキャッシングを実質的に ‘有効にする’ ため、設定すべき最も重要なヘッダーです。 このヘッダーが存在し、キャッシングを有効にする値が設定されている場合、ブラウザはそのファイルを指定されている期間だけキャッシュします。 このヘッダーがない場合、ブラウザは、以降の各リクエストでファイルを再要求します。

public​ リソースは、エンドユーザーのブラウザだけでなく、他の多くのユーザーに対応している可能性のあるすべての中間プロキシもキャッシュできます。

Cache-Control:public

private​ リソースは中間プロキシによってスキップされ、エンドクライアントのみがキャッシュできます。

Cache-Control:private

Cache-Control​ ヘッダーの値は合成値です。つまり、リソースがパブリックまたはプライベートのどちらであるかを示すと共に、古くなったとみなされるまでキャッシュできる最長時間を示します。max-age​ 値には、リソースがキャッシュされるタイムスパン (秒単位) が設定されます。

Cache-Control:public, max-age=31536000

Cache-Control​ ヘッダーがクライアント側のキャッシングを有効にし、リソースの max-age​ を設定するのに対して、Expires​ ヘッダーは、そのリソースが有効でなくなる特定の時点を指定するために使用されます。

Expires

Cache-Control​ ヘッダーに付随している場合、Expires​ は単純に、キャッシュされたリソースが有効であるとみなされなくなる日付を設定します。 この日付以降、ブラウザは、リソースの新しいコピーを要求します。それまでは、ブラウザのローカルにキャッシュされたコピーが使用されます。

Expires​ と max-age​ の両方が設定されている場合は、max-age​ が優先されます。

Cache-Control:public
Expires: Mon, 25 Jun 2012 21:31:12 GMT

Cache-Control​ と Expires​ がブラウザに、次にネットワークからリソースを取得する時点​を指示するのに対して、いくつかの追加ヘッダーはネットワークからリソースを取得する方法​を指定します。これらのタイプのリクエストは、条件付きリクエストと呼ばれます。

条件付きリクエスト

条件付きリクエストは、ブラウザがサーバーにリソースの更新されたコピーがあるかどうかを問い合わせることができるリクエストです。 ブラウザが、保持しているキャッシュされたリソースに関する情報を送信すると、サーバーは更新されたコンテンツが返されるべきか、またはブラウザのコピーが最新であるかを判定します。後者の場合は、304 (Not Modified) の HTTP ステータスが返されます。

条件付きリクエスト

条件付きリクエストではネットワーク経由で呼び出しが起動されますが、変更されていないリソースの場合は空のレスポンス本体が生成されるため、そのリソースがエンドクライアントに戻されるコストが節約されます。バックエンドサービスもまた、多くの場合、リソースの最終更新日をそのリソースにアクセスすることなく非常にすばやく判定できるため、それ自体で処理時間が大幅に節約されます。

時間ベース

時間ベースの条件付きリクエストによって、コンテンツは確実に、要求されたリソースが、ブラウザのコピーがキャッシュされた後に変更されている場合にのみ転送されます。キャッシュされたコピーが最新である場合、サーバーは 304 のレスポンスコードを返します。

条件付きリクエストを有効にするために、アプリケーションは Last-Modified​ レスポンスヘッダーを使用してリソースの最終更新時刻を指定します。

Cache-Control:public, max-age=31536000
Last-Modified: Mon, 03 Jan 2011 17:45:57 GMT

次にこのリソースを要求するとき、ブラウザは If-Modified-Since​ リクエスト​ヘッダーを使用して、この日付以降に変更されている場合にのみリソースのコンテンツを送信するよう求めます。

If-Modified-Since: Mon, 03 Jan 2011 17:45:57 GMT

そのリソースが Mon, 03 Jan 2011 17:45:57 GMT​ 以降に変更されていない場合、サーバーは 304​ レスポンスコードと共に空の本体を返します。

コンテンツベース

ETag​ (エンティティタグ) は、その値がリソースコンテンツのダイジェスト (MD5 ハッシュなど) である点を除き、Last-Modified​ ヘッダーと同様に動作します。 これにより、サーバーは、リソースのキャッシュされたコンテンツが最新のバージョンと異なるかどうかを特定できます。

このタグは、最終更新日を特定することが困難な場合に役立ちます。

Cache-Control:public, max-age=31536000
ETag: "15f0fff99ed5aae4edffdd6496d7131f"

ブラウザの以降のリクエストでは、If-None-Match​ リクエスト​ヘッダーが、リソースの要求された最終バージョンの ETag 値と共に送信されます。

If-None-Match: "15f0fff99ed5aae4edffdd6496d7131f"

If-Modified-Since​ ヘッダーと同様に、現在のバージョンが同じ ETag 値を持っている場合 (その値がブラウザのキャッシュされたコピーと同じであることを示す) は、304 の HTTP ステータスが返されます。

視認性

最新のブラウザには、堅牢なリクエスト/レスポンス可視化および内観ツールが含まれています。Chrome と Safari の両方にある Web Inspector では、Network​ (ネットワーク) タブにレスポンスとリクエストヘッダーが表示されます。

さまざまなキャッシュヘッダーを使用するサンプルアプリケーションのコードは GitHub​ にあります。

これは、アプリケーションによって返される一連のデフォルトヘッダー (キャッシュディレクティブはなし) を示す初期リクエストの例です。

HTTP ヘッダーのデフォルト

cache​ クエリパラメータを追加すると、アプリケーションは Cache-Control​ と Expires​ の両方のヘッダーでのキャッシングを有効にします (どちらも後で 30 秒に設定されます)。

キャッシュ制御のデフォルト

リクエストに etag​ パラメータを追加すると、サンプルアプリは JSON コンテンツの ETag ダイジェストを指定するようになります。

ETag のデフォルト

より深い調査でも、ETag ベースの条件付きリクエストは期待どおりに動作します。初期のリクエストでは、ブラウザがサーバーからファイルをダウンロードします。

HTTP 200 での単純なダウンロード

以降のリクエストでは、サーバーはブラウザの ETag チェックに 304 (Not Modified) の HTTP ステータスで応答しています。これにより、ブラウザは独自のキャッシュされたコピーを使用します。

HTTP 304 でのキャッシュのダウンロード

ユースケース

静的アセット

通常の使用状況では、すべての開発者の出発点は、変更されないアプリケーション内のファイルに積極的なキャッシング方式を追加することです。 これには通常、画像、CSS ファイル、JavaScript ファイルなどの、アプリケーションによって処理される静的ファイルが含まれます。これらのファイルは一般に、各ページで再要求されるため、少ない労力で大きなパフォーマンス向上が得られます。

このような場合は、要求の時点から 1 年後までの max-age 値を持つ Cache-Control ヘッダーを設定する必要があります。Expires も同じ値に設定することをお勧めします。

1 年は 31536000 秒です。

Cache-Control:public; max-age=31536000
Expires: Mon, 25 Jun 2013 21:31:12 GMT

それより長い期間は RFC​ でサポートされておらず、無視される可能性があるため、一般に、これを超える値を設定することはお勧めしません。

動的コンテンツ

動的コンテンツには、まったく異なる処理が求められます。 リソースごとに、開発者はそれをどの程度キャッシュできるか、および古いコンテンツの処理がユーザーにどのような影響を与える可能性があるかを評価する必要があります。 2 つの例として、ブログ RSS フィードのコンテンツ (数時間に 1 回より頻繁には変更されない) と、ユーザーの Twitter タイムラインを起動する JSON パケット (数秒に 1 回更新される) が挙げられます。 これらの場合は、エンドユーザーに対して問題を発生させることなく可能であると思われる期間だけリソースをキャッシュすることが妥当です。

プライベートコンテンツ

プライベートコンテンツ (これは機密情報であり、セキュリティ対策に従う必要があるとみなされる) には、さらなる評価が必要です。 開発者は、特定のリソースのキャッシュ可能性を判定する必要があるだけでなく、ユーザーの制御の範囲外にある可能性のあるファイルをキャッシュする中間キャッシュ (Web プロキシなど) を置くことの影響も考慮する必要があります。 疑いがある場合は、これらの項目をまったくキャッシュしないことが安全なオプションです。

エンドクライアントのキャッシングが引き続き望ましい場合は、リソースをプライベートに (つまり、エンドユーザーのブラウザのキャッシュ内に) のみキャッシュするよう求めることができます。

Cache-Control:private, max-age=31536000

キャッシュの防止

きわめて安全なリソースや変わりやすいリソースには多くの場合、キャッシングは必要ありません。たとえば、ショッピングカートのチェックアウトプロセスに関連するすべてのものです。ただし、最新の Web ブラウザの多くは独自の内部アルゴリズムに基づいて項目をキャッシュするため、単にキャッシュヘッダーを省略してもうまく機能しません。このような場合は、項目をキャッシュしないよう明示的にブラウザに指示することが必要です。

public​ や private​ に加えて、Cache-Control​ ヘッダーでは no-cache​ と no-store​ を指定できます。これは、どのような状況でもリソースをキャッシュしないようブラウザに指示します。

IE では no-cache​ が使用され、Firefox では no-store​ が使用されるため、両方の値が必要です。

Cache-Control:no-cache, no-store

実装

HTTP キャッシングの背後にある概念を理解したら、次のステップは、これをアプリケーションで実装することです。最新の Web フレームワークでは、これがきわめて簡単な作業になっています。

​言語/フレームワーク ​チュートリアル
​Ruby/Rails
  • ​Rails を使用した Ruby での HTTP キャッシング
  • ​HTTP キャッシュストアを提供するための ​Memcached での Rack::Cache の使用

関連カテゴリー

  • アプリのパフォーマンス
定期的なジョブとカスタムクロックプロセス Memcache を最大限に活用する

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure
  • .NET

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • © 2025 Salesforce, Inc. All rights reserved. Various trademarks held by their respective owners. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States
  • heroku.com
  • Legal
  • Terms of Service
  • Privacy Information
  • Responsible Disclosure
  • Trust
  • Contact
  • Cookie Preferences
  • Your Privacy Choices