Conditional GET: その概要、条件付きリクエストの仕組み

著者: IT Sectr 公開日: 2026-06-14 読了時間: 7 分

Conditional GET — クライアントが完全なダウンロード前にキャッシュされたリソースの最新性を確認できるHTTPメカニズム。クライアントはIf-None-Match(ETagを含む)またはIf-Modified-Since(日付を含む)ヘッダーとともにGETリクエストを送信し、リソースが変更されていない場合、サーバーはレスポンスボディなしで304 Not Modifiedを返します。MDN Web Docs、2025によると、条件付きリクエストはサーバーとクライアントのネットワークトラフィックを削減します。304 Not Modifiedは、効率的なモバイルアプリケーション同期のための重要なHTTPステータスです。

重要なポイント

  • Conditional GET — キャッシュの最新性を確認するためのIf-None-MatchまたはIf-Modified-Sinceヘッダー付きHTTPリクエスト。
  • 304 Not Modified — リソースが変更されていないことを示すサーバー応答。レスポンスボディは送信されず、トラフィックを節約。
  • If-None-Match — ETag(バージョンハッシュ)を含むヘッダー。リソース内容レベルでの正確な検証を提供。
  • If-Modified-Since — 最終更新日を含むヘッダー。実装は簡単だが精度は低い(1秒分解能)。
  • 効率性 — Conditional GETは変更されていないリソースの同期中にデータ量を80–95%削減。

HTTPにおけるConditional GETとは

Conditional GETは、1つ以上の条件付きヘッダーを含むGETリクエストであり、サーバーはそれらに基づいて完全な応答を返すか、304 Not Modifiedステータスのみを返すかを決定します。主な目的は、前回のリクエスト以降にリソースが変更されていない場合に、応答ボディの送信を回避することです。これはRFC 7232で定義された基本的なHTTPキャッシングメカニズムです。

モバイルアプリケーションにとって、Conditional GETはネットワークトラフィックを最適化する最も効果的な方法の1つです。典型的なシナリオ:アプリを開くとき、クライアントはフィード、プロフィール、設定を読み込むために一連の条件付きGETリクエストを送信します。データが変更されていない場合、アプリは304を受信し、ローカルコピーを使用します。これには秒ではなくミリ秒かかり、モバイルデータを消費しません。

Google Web Fundamentals(2025)によると、モバイルアプリケーションに条件付きGETリクエストを実装すると、繰り返し訪問時の平均読み込み時間が40–60%短縮され、更新頻度の低いページのトラフィック使用量が70–90%削減されます。効果は特に低速接続(3G、Edge)で顕著であり、1バイト1バイトが重要です。

条件付きGETリクエストの仕組み

プロセスは3つのステップで構成されます。最初 — クライアントは通常のGETリクエストを送信し、サーバーはキャッシュヘッダー(ETag、Last-Modified)とともにリソースを返します。2番目 — クライアントはリソースとそのバリデーターをローカルに保存します。3番目 — 繰り返しリクエスト時に、クライアントはIf-None-Match(ETag用)および/またはIf-Modified-Since(Last-Modified用)とともにGETを送信します。サーバーはバリデーターをチェックし、リソースが変更されていない場合は304、新しいデータがある場合は200で応答します。

サーバーは両方のヘッダーが存在する場合、ETagをLast-Modifiedより優先します。これは、ETagの方がより正確な検証を提供するためです — コンテンツハッシュは変更があると変わりますが、Last-Modifiedは1秒の分解能しかありません。ETagが一致する場合、サーバーはLast-Modifiedをチェックせずに直ちに304を返します。

リクエストシーケンスにおける完全なConditional GETサイクルの例:

kotlin
// ステップ 1: 最初のリクエスト — データとETagを取得
GET /api/profile
Response: 200 OK
ETag: "33a64df551425fcc55e"
Body: { "name": "Alice" }

// ステップ 2: リクエストを繰り返す — If-None-Match付き
GET /api/profile
If-None-Match: "33a64df551425fcc55e"
Response: 304 Not Modified
// レスポンスボディなし — ローカルコピーを使用

2番目のリクエストでは、サーバーはIf-None-MatchからのETagを現在のリソースハッシュと比較します。一致する場合、ボディなしで304を返します — クライアントはキャッシュされたデータを引き続き使用します。これがConditional GETの本質です:最小限のトラフィックで最大のデータ最新性。

Conditional GETと通常のGETの比較

通常のGETリクエストは常にボディ付きの完全な200 OK応答を返します。リソースが変更されていない場合でも、サーバーはすべてのデータを再度送信します。これは小さなリソースや稀なリクエストには許容されますが、起動のたびに数百のリクエストを行うモバイルアプリケーションでは、このアプローチは過剰なトラフィックとバッテリー消費につながります。

Conditional GETはヘッダーの形でオーバーヘッドを追加します(通常1リクエストあたり50–200バイト)が、304応答でキロバイトやメガバイトを節約します。リソースが大きいほど、条件付きリクエストのメリットが大きくなります。10 KB以上の画像、データリスト、JSONドキュメントの場合、Conditional GETは最初の繰り返しリクエストから効果を発揮します。

2つのアプローチの比較特性:

パラメータ通常のGETConditional GET
トラフィック(変更なし)完全な応答ヘッダーのみ(~200バイト)
レイテンシ完全ダウンロードミリ秒(304)
サーバー負荷生成+転送ETagチェックのみ
実装の複雑さ最小ETag保存が必要
大規模データの効率低い高い

Kotlinでの実装例

完全な実装を見てみましょう — OkHttpとRoomを使用したKotlinでのConditional GET(ETag保存用)。タスクリストアプリケーションがサーバーからタスクを読み込み、トラフィックを最小限に抑えるために条件付きリクエストを使用します。ETagはセッション間で永続化するためにローカルデータベースに保存されます。

KotlinでのConditional GETを持つリポジトリ:

kotlin
class TaskRepository(
    private val api: TaskApi,
    private val etagDao: EtagDao
) {
    suspend fun getTasks(): List<Task> {
        val savedEtag = etagDao.getEtag("tasks")

        val response = api.fetchTasks(
            ifNoneMatch = savedEtag
        )

        return when (response.code()) {
            304 -> taskDao.getAll() // ローカルキャッシュから
            200 -> {
                response.header("ETag")?.let {
                    etagDao.saveEtag("tasks", it)
                }
                val tasks = response.body() ?: emptyList()
                taskDao.replaceAll(tasks)
                tasks
            }
            else -> throw Exception(
                "Sync failed: ${response.code()}")
        }
    }
}

TaskRepositoryは応答コードをチェックします:304は変更なしを意味し、データはローカルのRoomキャッシュから返されます。200の場合、新しいETagが保存され、タスクがローカルデータベースで更新されます。このパターンはREST API同期を備えたモバイルアプリケーションの標準です。

モバイル開発におけるConditional GETの使用

Conditional GETは広く使用されています — モバイルアプリケーションでのデータ同期最適化に。主なシナリオ:ニュースフィードの読み込み(Twitter、Instagramは定期的にIf-None-Match付きでAPIをポーリング)、ユーザープロフィールの更新、通知リストの読み込み、タスクの同期。各ケースで、アプリはデータを再ダウンロードせずに最新性を確認できます。

オフラインファーストアプリケーションの場合、Conditional GETは同期の最初の段階として機能します。アプリはまず、前回の同期以降にローカルで変更されたすべてのリソースに対して条件付きGETリクエストを送信します。304のリソースはダウンロード不要です。その後、アプリはローカルの変更に対してPUT/POSTを送信します。この2フェーズアプローチにより、トラフィック消費を最小限に抑えます。

競合解決と組み合わせることで、Conditional GETは効率的な競合検出を可能にします。クライアントが新しいデータとともに200を受信したが(リソースが変更された)、未送信のローカル変更がある場合 — 競合が登録されます。クライアントはLWWを適用するか(ローカル変更が失われる)、マージ戦略を開始してローカルとリモートの変更をマージできます。Meta Engineering Blog(2025)によると、MessengerでのConditional GET実装により、平均同期トラフィックが73%削減されました。

よくある質問

Conditional GETリクエストとは?

Conditional GET — 条件付きヘッダー(If-None-Match、If-Modified-Since)付きのHTTP GETリクエスト。リソースが変更されていない場合はサーバーが304 Not Modifiedを返し、新しいデータがある場合は200を返します。効率的なキャッシングメカニズムです。

Conditional GETと通常のリクエストの違いは?

通常のGETは常にボディ付きの完全な応答を返します。Conditional GETはバージョンチェックヘッダー(ETag、日付)を追加します。データが変更されていない場合、サーバーはボディなしで304を返し、トラフィックと読み込み時間を節約します。

キャッシングにConditional GETを使用する方法

効果的なキャッシングのために、各サーバー応答からETagとLast-Modifiedをローカルデータベースに保存します。次のリクエスト時に、それらをIf-None-MatchおよびIf-Modified-Sinceヘッダーで送信します。304の場合、ローカルキャッシュのデータを使用します。

Conditional GETはどのようにトラフィックを節約する?

304応答時、サーバーはレスポンスボディを送信せず — ヘッダーのみ(~200バイト)を送信します。50 KBのリソースの場合、99.6%のトラフィック節約になります。1日50回同期するアプリの場合、月間で数十メガバイトの節約になります。

同期にConditional GETは使用できる?

はい、これは標準的なアプローチです — デルタ同期において。クライアントはConditional GETを介して各リソースの最新性を確認し、変更されたリソースのみをダウンロードし、ローカルの変更を送信します。このアプローチはTwitter、Instagram、Telegram、およびほとんどの最新APIで使用されています。

まとめ

  • Conditional GET — 条件付きIf-None-MatchおよびIf-Modified-Sinceヘッダーを介してキャッシュされたリソースの最新性を確認するためのHTTPメカニズム。
  • 304 Not Modified — リソースが変更されていないことを示すサーバー応答。応答ボディは送信されず、トラフィックと読み込み時間を節約。
  • ETag vs Last-Modified — ETagはより正確(コンテンツハッシュ)、Last-Modifiedはよりシンプル(日付)。最大効率のために両方の組み合わせを推奨。
  • トラフィック節約 — 変更されていないリソースの場合、Conditional GETはリソースサイズに応じて転送データ量を70–95%削減。
  • 応用 — Twitter、Instagram、Telegram、およびほとんどの最新REST APIでの標準同期メカニズム。
  • 統合 — クライアント側ではローカルデータベースへのETag保存が必要。サーバー側では各リクエストでのETag生成と比較が必要。
  • 推奨 — モバイルAPIのすべてのGETエンドポイントにConditional GETを実装してください。これはユーザーにとって最大の効果を持つ最も安価な最適化です。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください