HTTPバージョンの話が出ると、たいていこんなことを考えます。 > 「結局、ウェブは全部HTTPじゃないの?1.1と2って何がそんなに違うの?」 > 「新しいバージョンのHTTP/2だけを使えばいいじゃない?」 まとめると: * **HTTP/1.1とHTTP/2は「完全に異なるプロトコル」というより、同じHTTPの意味(メソッド/ヘッダー/ステータスコードなど)をより効率的に送る方法の違い**です。 * 実際のサービスでは「どちらか一方を選ぶ」 のではなく、**サーバーが両方をサポートし、クライアントが選択できるようになっているのが一般的です。** 以下では、開発者の観点からポイントをまとめてみます。 --- 1. HTTP/1.1の簡単なまとめ ------------------ ### 1) テキストベースのプロトコル {#sec-b62f528b43df} HTTP/1.1は我々がよく見るリクエスト/レスポンス形式です。 ``` GET /index.html HTTP/1.1 Host: example.com Connection: keep-alive HTTP/1.1 200 OK Content-Type: text/html Content-Length: 1234 ... ``` * 人間が読める**テキストベース**なのでデバッグが簡単で、 * `curl`や`telnet`、`nc`などのツールでざっくり確認することができます。 ### 2) Persistent Connection + Pipelining {#sec-9182fd60d6bb} HTTP/1.0の大きな問題は、**リクエストごとに新しいTCP接続を開くこと**でしたが、 HTTP/1.1では基本的に**persistent connection (keep-alive)**が導入され、 1つの接続上で複数のリクエストを順番に送信できるようになりました。 さらに**HTTP pipelining**という機能もありましたが: * 応答を待たずにリクエストを連続して送信し、 * 順番に応答を受け取る方式です。 しかし、実際のブラウザではほとんど使用されておらず、 依然として**「順番に処理しなければならない構造」**なので、性能上の問題が残ります。 ### 3) HOL(Head-of-Line) Blocking問題 {#sec-aecc0ef09964} HTTP/1.1の象徴的なボトルネックが**HOL(Head-of-Line) Blocking**です。 * 1つの接続でリクエストを順番に処理しなければならないため、 * **最初のリクエストが遅くなると後ろのリクエストも一緒に待たされる**ことになります。 * そのため、ブラウザは1つのドメイン(origin)ごとに複数のTCP接続を開く(例えば最大6個)ことでこの問題を緩和してきました。 要約すると: > HTTP/1.1は「複数のパイプを作ることでボトルネックを減らす方式」です。 > (複数のTCP接続) --- 2. HTTP/2は何が違うのか? ----------------- HTTP/2の目標は明確です。 * **遅延(latency)を減らすこと** * **ネットワークリソースをより効率的に使うこと** 核心的なキーワードを挙げると: 1. **バイナリフレーミング(Binary Framing)** 2. **ストリーム(Stream)ベースのマルチプレクシング(Multiplexing)** 3. **ヘッダー圧縮(HPACK)** 4. (元々は)**サーバープッシュ(Server Push)** – *実質的にブラウザで死去* ### 2-1. テキスト → バイナリフレーミング {#sec-5170211334a2} HTTP/1.1は行単位のテキストパースですが、HTTP/2ではすべてを**フレーム(frame)**というバイナリの塊に分けて送信します。 * ヘッダーはHEADERSフレーム * 本文はDATAフレーム * これらのフレームは特定の**ストリームID**に属します。 開発者が直接フレームに触れることはほとんどありませんが、 これによって**マルチプレクシング、ヘッダー圧縮、優先順位**などの機能を実装できます。 ### 2-2. マルチプレクシング(Multiplexing) {#sec-a3d18e67ff40} 最も体感できる違いです。 * HTTP/1.1: 1つのTCP接続で**リクエスト-レスポンスを順番に**処理 * HTTP/2: 1つのTCP接続で**複数のストリームを同時に**流します。 つまり、 > 「複数のTCP接続を開く必要がなく、 > 1つの接続内でリクエストとレスポンスを組み合わせて同時に送信すること」 こうすることで: * 1つのHTMLページが数十〜数百のリソースを取得しなければならない場合でも、 * 1つの接続のみを維持しながら**同時に**取得できるため、 * モバイル環境や高RTT環境では特に利益が大きくなります。 ただし、依然として**TCPレベルではHOL Blocking**が残るため、この部分はHTTP/3(QUIC)がさらに改善した領域です。 ### 2-3. ヘッダー圧縮(HPACK) {#sec-c6f254b27082} HTTPリクエスト/レスポンスヘッダーにはかなりの重複があります。 * `Cookie`、`User-Agent`、`Accept-*`など * 毎回のリクエストで数百KBも含まれることがあります。 HTTP/2は**HPACK**というヘッダー圧縮方式を使って、 これらのヘッダーの間の重複を減らします。 * よく使うヘッダーはテーブルに登録し、短いインデックスで送信 * 以前のリクエストとは異なった部分のみを効率的にエンコード これにより、特に**リクエストが多いSPA / リソースの多いページ**で大きな利益があります。 ### 2-4. サーバープッシュ(Server Push)は事実上死去 {#sec-b574c5aba1ce} HTTP/2の初期には「サーバーがクライアントがリクエストする前にCSS/JSなどを先にプッシュする機能」である**サーバープッシュ(Server Push)**も大きな利点とされていましたが、実際には: * 実装難易度が高く、 * キャッシュ/重複リソースの問題 * 実際の性能改善がわずかで、逆に悪化するケースも などがあり、**Chrome/Chromium系は2022年以降デフォルトで無効化**され([Chrome for Developers](https://developer.chrome.com/blog/removing-push?utm_source=chatgpt.com "Remove HTTP/2 Server Push from Chrome | Blog")) Firefoxも2024年にサポートを削除するなど、**ブラウザエコシステムでは事実上終わった機能**です。 そのため、最近HTTP/2の話をする際、サーバープッシュは「歴史的な機能」としてだけ見ることができます。 --- 3. HTTPS、ALPN、そして「h2 vs http/1.1の選択」 ------------------------------------ 実際のサービスで「HTTP/1.1を使うべきか、HTTP/2を使うべきか?」は、 **クライアントとサーバーがTLSハンドシェイクの過程で自動的に交渉します。** これを担うのが**ALPN(Application-Layer Protocol Negotiation)**というTLS拡張です。 * クライアント: 「私は`h2`と`http/1.1`の両方ができます」 * サーバー: 「では`h2`でいきましょう」 (または「私は`http/1.1`しかできません」) Apacheの例設定: ``` Protocols h2 http/1.1 ``` こう設定しておくと: * HTTP/2をサポートする最新のブラウザは**自動的にHTTP/2(h2)を使用** * 古いクライアントは**自動的にHTTP/1.1で通信** ほとんどの主要なブラウザはすでにHTTP/2をよくサポートしており、 かなりの数のウェブサイトがHTTP/2を有効にしています。 --- 4. 「どんな場合に分けて使いますか?」 – 開発視点の整理 ------------------------------ 質問の核心であるこの部分をケース別に見ていきます。 ### 4-1. 一般的なウェブサービス(ブラウザ対象) {#sec-fede767e37e0} **正しい戦略に近い:** > 「HTTPS + HTTP/2を基本にオンにし、 > HTTP/1.1はフォールバックとしてそのままにしておけば良い。」 * ほとんどのウェブサーバー(Nginx、Apache、Envoyなど)とCDNは、 HTTP/2サポートオプションをオンにするだけで自動交渉します。 * アプリケーションレベルで「このリクエストは1.1、あれは2で送ろう」と直接分けることはほとんどありません。 つまり、**新しいサービスを作る場合、‘HTTP/2をオンにしたHTTPS’を基本設定と考えれば良い**のです。 ### 4-2. 内部API / マイクロサービス通信 {#sec-c41b2ee365dc} ここではもう少し選択肢があります。 * すでに**REST + HTTP/1.1**でうまく動いているなら、 わざわざHTTP/2に書き直す必要はありません。 * ただし、 + 同一サービス間で**短いリクエストを非常に多く**やり取りする場合や、 + gRPCなどの**HTTP/2ベースのプロトコル**を使用する場合は、 → HTTP/2を使うのが自然です。 つまり、 * 「既存のレガシーREST API」→ 1.1を維持 + 必要に応じてプロキシ/ロードバランサーでHTTP/2ターミネーション * 「新たにgRPC導入、高頻度マイクロサービス呼び出し」→ HTTP/2を積極的に活用 ### 4-3. デバッグ、ロギング、レガシー環境 {#sec-5786bea484ae} HTTP/1.1が今でも有用な状況もあります。 * **テキストベースなのでtcpdumpやWiresharkで内容が見やすい** * 古いプロキシ/ファイアウォール/クライアントはHTTP/2をサポートしないかもしれません。 * 単純な社内ツール、テストサーバーなどでは、わざわざHTTP/2を使わなくても十分です。 実際には多くの環境で: * **外部(ブラウザ) ↔ フロントプロキシ(CDN/Load Balancer)** : HTTP/2 * **プロキシ ↔ バックエンドサービス** : HTTP/1.1 構造が混ざり合っているケースが多いです。 --- 5. 「HTTP/2だけ使ったらダメですか?」への現実的な回答 ------------------------------- 理論的には: > 「新しく作る公開ウェブサービスであれば、HTTP/2を基本に考えても問題ありません。」 が正しいです。 しかし実務的には: 1. **HTTP/1.1を完全になくすのは難しい** * 古いクライアントや特別な環境は、今でも1.1しか使えません。 * デバッグ/ツール/内部システムなどでは、1.1の方が楽な場合もあります。 2. **サーバー視点では「両方をサポートする」ことが一般的** * ウェブサーバー設定で`h2 http/1.1`のようにオンにして、 * クライアントがサポートする最高のプロトコルを自動的に選択させることが多いです。 3. **HTTP/3(QUIC)まで考慮する時代** * 最新のブラウザやサービスは、すでにHTTP/3もサポートしています。 * しかし、これも通常「HTTP/1.1 + HTTP/2 + HTTP/3」を同時に開いておき、 クライアントが交渉で選ぶ構造です。 したがって、現実的な結論は: > 「HTTP/2だけを固執するより、 > **HTTP/2を基本にオンにし、HTTP/1.1は自然なフォールバック**としておくのがベストです。」 です。 --- ![HTTPバージョンによる転送方式の比較](/media/whitedec/blog_img/comparing_http1_1_vs_2.webp "HTTPバージョンによる転送方式の比較") 6. まとめ ------ 一度に整理すると: * **HTTP/1.1** + テキストベース + persistent connection + (理論上の) pipelining + HOL Blocking問題によりブラウザは複数のTCP接続を開いて使用 * **HTTP/2** + バイナリフレーミング + 1つのTCP接続で複数のストリームを同時に処理するマルチプレクシング + HPACKヘッダー圧縮 + サーバープッシュは実質的に実戦で死去 * **使用戦略** + 外部ウェブ(ブラウザ対象):HTTPS + HTTP/2をオンにし、HTTP/1.1はフォールバック + 内部API:既存のRESTは1.1を維持もOK、高頻度/ストリーミング/gRPCならHTTP/2を積極的に活用 + デバッグ/レガシー:今でもHTTP/1.1が便利で役に立つ 開発者が覚えておくべき一言: > 「アプリコードでバージョンを選ぼうと悩まずに、 > **サーバーでHTTP/2をオンにし、残りはプロトコル交渉(ALPN)に任せましょう。**」