LASSIC Media らしくメディア
HTTP/2の仕組みとHTTP/1.1との違い、多重化と圧縮
監修・編集責任者:牛尾 昭昌(株式会社LASSIC 執行役員)
この記事の結論
- HTTP/2は、HTTPの意味はそのままに、1本のTCP接続の中で複数の要求と応答をフレームに分けて同時に運ぶ方式です。
- HTTP/1.1との違いは多重化・ヘッダー圧縮・バイナリのフレームで、TCPでの順番待ちは残ります。
- サーバープッシュのような使われなくなった機能に頼らず、有効化はALPNで選ばれたプロトコルで確かめます。
※ 本記事は2026年10月時点の公式情報(省庁・公的機関、および製品やサービスを提供する事業者が公開している資料)に基づきます。
Webサーバーの設定にhttp2 onと書いたのに、ブラウザーの開発者ツールで見るとHTTP/1.1のまま。サーバープッシュは今も使えるのか——。HTTP/2を扱う現場では、こうした迷いがよく起こります。HTTP/2とは、HTTPのやり取りの意味を変えずに、1本のTCP接続で複数の要求と応答を同時に運べるようにしたHTTPのバージョンです。
本記事では、システム開発やWebサービスの運用に携わる方に向けて、HTTP/2の仕組みとHTTP/1.1との違い、確かめ方とつまずきやすい点を、RFCと公式ドキュメントをもとに整理します。
目次
HTTP/2とは
HTTP/2の現在の仕様は、2022年6月に公開されたRFC 9113です。以前のRFC 7540とRFC 8740は、これで置き換えられました。RFC 9113は、HTTP/2はフィールド(ヘッダー)の圧縮と、同じ接続での複数のやり取りの同時進行によって、ネットワーク資源をより効率よく使い、遅延を減らすと説明しています。*1
押さえておきたいのは、HTTP/2が変えたのは「運び方」であり、「意味」ではない点です。GETやPOSTといったメソッド、ステータスコード、ヘッダーの意味は、すべてのバージョンに共通する仕様としてRFC 9110にまとめられ、HTTP/1.1のメッセージの書き方と接続の扱いはRFC 9112という別の文書になっています。*2 そのため、アプリケーションが返す200や404の意味はHTTP/2でも変わりません(ステータスコードそのものは「HTTPステータスコードの基礎」で扱っています)。
HTTP/2はTCP接続の上で動くアプリケーション層のプロトコルです。TCPの接続確立の手順はここでは扱わず、TCPの接続を1本張ってその中を細かく使い分ける、と押さえておけば十分です。
フレームとストリームの仕組み
HTTP/2でやり取りの最小単位は「フレーム」です。どのフレームも9バイトの固定のヘッダーで始まり、そこにペイロードの長さ(24ビット)、種類(8ビット)、フラグ(8ビット)、ストリームの識別子(31ビット)が入ります。ペイロードは、受け手が設定で許さない限り16,384バイトを超えてはいけません。*1 人が読める文字列ではなくバイナリの形なので、受け手は区切りを探さずに読み進められます。
要求や応答のヘッダーはHEADERSフレーム、本文はDATAフレームで運びます。設定を伝えるSETTINGSや、受け取れる量を知らせるWINDOW_UPDATEも同じ形です。
1組の要求と応答は、それぞれ「ストリーム」に割り当てられます。クライアントが始めるストリームには奇数、サーバーが始めるものには偶数の識別子を使います。上の図のように、HTMLのストリーム1、CSSのストリーム3、JavaScriptのストリーム5のフレームを1本の接続に交互に流せるので、ある応答が遅れても、ほかの応答は止まらずに届きます。これが多重化です。
多重化を支えるのがフロー制御です。受け手は各ストリームと接続全体について受け取れる量を知らせ、送り手はその範囲でしか送りません。初期値はどちらも65,535バイトです。同時に開けるストリームの数はSETTINGS_MAX_CONCURRENT_STREAMSで伝え、RFC 9113は100以上にすることを勧めています。*1
HTTP/1.1との違い
HTTP/1.1にも、応答を待たずに次の要求を送る「パイプライン」がありました。しかしRFC 9112は、サーバーは要求を受け取った順に応答を返さなければならないと定めています。*3 前の応答が遅れると後ろが待たされるため、ブラウザーは同じサーバーに複数のTCP接続を張って並行させてきました。
| 項目 | HTTP/1.1 | HTTP/2 |
|---|---|---|
| メッセージの形 | テキスト(改行で区切る) | バイナリのフレーム |
| 並行のしかた | 接続を複数張る。パイプラインは受け取った順に応答 | 1本の接続でストリームを多重化 |
| ヘッダー | 毎回そのまま送る | HPACKで圧縮して送る |
| 接続ごとのヘッダー | Connection・Keep-Aliveなどを使う | 接続ごとのヘッダーは使わない |
| TLS上での開始 | ALPNではhttp/1.1 | ALPNでh2を選ぶ |
HTTP/1.1で接続を使い回す仕組みは、1本の接続で要求を1つずつ順に処理するものです。「接続を使い回す」と「同時に運ぶ」は別の話です。HTTP/2ではConnection、Keep-Alive、Transfer-Encoding、Upgradeといった接続ごとのヘッダーを含むメッセージは不正な形として扱われ、HTTP/1.1から変換する中継装置はこれらを取り除かなければなりません。
ただし、RFC 9113自身が、TCPでの順番待ちはこのプロトコルでは解決しないと明記しています。パケットが1つ失われると、TCPが再送を待つ間、同じ接続の全ストリームが止まります。この点を土台から変えたのがHTTP/3で、違いは「HTTP/3・QUIC対応の高速化と外注のポイント」で取り上げています。
ヘッダー圧縮と優先度
HTTPのヘッダーは要求ごとにほとんど同じ内容を繰り返します。HTTP/2はこれをHPACKで圧縮します。仕様のRFC 7541によると、前身のSPDYはDEFLATEで圧縮していましたが、CRIMEと呼ばれる攻撃で情報が漏れる危険が示され、新しい方式が作られました。*4
HPACKは、よく使うヘッダーをあらかじめ並べた静的テーブルと、接続の中で送ったヘッダーを覚えておく動的テーブルを使い、2回目以降は番号で送ります。動的テーブルの大きさは初期値が4,096バイトで、SETTINGS_HEADER_TABLE_SIZEで変えられます。*1
優先度の扱いは、仕様の改訂で大きく変わりました。RFC 7540の優先度の仕組みは広く採用されず、RFC 9113で非推奨になり、代わりにRFC 9218の方式が勧められています。RFC 9218では、要求にPriorityヘッダーを付け、緊急度uを0〜7(小さいほど優先、既定は3)、少しずつ処理できるかどうかをiで伝えます。iの既定は偽です。*5
具体例:ALPNで確かめる
TLSで暗号化する接続では、HTTP/2を使うかどうかはTLSのハンドシェイクの中で決まります。そのために使うのが、TLSの拡張であるALPNです。*6 クライアントが候補としてh2とhttp/1.1を送り、サーバーが1つを選びます。https のURIへの要求ではALPNを使い、HTTP/2を表す識別子はh2です。
nginxでは、ngx_http_v2_moduleを組み込んだうえで、serverの中にhttp2 onと書きます。このディレクティブは1.25.1から使えるもので、既定はoffです。TLS上でHTTP/2を受けるにはALPNが必要で、OpenSSL 1.0.2から使えるとされています。*8
# nginx 1.25.1以降(公式ドキュメントの設定例)
server {
listen 443 ssl;
http2 on;
ssl_certificate server.crt;
ssl_certificate_key server.key;
}
有効になったかは、ALPNで実際にどれが選ばれたかで確かめます。下はPythonの標準ライブラリだけで、サーバーが選んだものを表示する例です。2026年9月30日に公開サイト2つへ実行した出力を載せています。
import socket, ssl
def negotiate(host, offer):
ctx = ssl.create_default_context()
ctx.set_alpn_protocols(offer) # ClientHelloで候補を伝える
with socket.create_connection((host, 443), timeout=10) as sock:
with ctx.wrap_socket(sock, server_hostname=host) as tls:
return tls.selected_alpn_protocol(), tls.version()
for host in ["www.rfc-editor.org", "nginx.org"]:
print(host, negotiate(host, ["h2", "http/1.1"]))
# 出力(2026-09-30 実行)
# www.rfc-editor.org ('h2', 'TLSv1.3')
# nginx.org ('http/1.1', 'TLSv1.2')
1つ目のサイトはh2を選び、HTTP/2で話します。2つ目は、h2を候補に出してもhttp/1.1を選びました。HTTP/2に対応していないサーバーでも、このように接続は失敗せず、HTTP/1.1で続きます。設定を変えたあとは、選ばれたプロトコルを確かめます。curlなら–http2を付け、-w で http_version を表示させる方法もあります。*9
実務での使いどころ
HTTP/2が効きやすいのは、1つの画面を開くのに小さなファイルや API の要求がたくさん発生する場面です。並行させるために接続を増やすといったHTTP/1.1向けの工夫の一部は、多重化で要らなくなります。RFC 9113も、HTTP/1.xより少ないTCP接続で済むので、ほかの通信との競合が減ると述べています。
社内のサービス間の通信でもHTTP/2は使われます。代表がgRPCで、HTTP/2の上で双方向のストリーミングを行います(設計の考え方は「gRPC API開発の外注」で扱っています)。
ロードバランサーやCDNを置く構成では、入口でHTTP/2を受け、奥のサーバーへはHTTP/1.1で転送することも珍しくありません。どこまでがHTTP/2なのかを構成図に書いておくと、障害の切り分けがしやすくなります。
つまずきやすい点
まず、サーバープッシュです。HTTP/2には、要求される前にサーバーが応答を送る仕組みがあります。しかしRFC 9113は、要求を正しく予測するのが難しく、予測を外すと性能が落ちると書いています。Chromeは2022年の公式ブログで、Chrome 106から既定で無効にすると告知し、HTTP/2のサイトのうち使っていたのは1.25%で、その後0.7%に減っていたとしています。代わりに勧められたのが、先に取りに来てほしいものをヒントとして伝える103 Early Hintsです。*7 nginxでもhttp2_pushは1.25.1で廃止され、early_hintsの利用が案内されています。
次に、暗号化しないHTTP/2(h2c)です。HTTP/1.1のUpgradeヘッダーでh2cに切り替える方法は、広く使われなかったためRFC 9113で非推奨になりました。暗号化しないで使うなら、相手の対応が分かっている前提で最初からHTTP/2で話す「事前の知識」による方法になります。
確認の道具にも落とし穴があります。curlの公式マニュアルは、–http2が動くには、libcurlがHTTP/2に対応して組まれている必要があるとしています。*9 実際、今回の作業環境のcurlでは、–http2を付けると「the installed libcurl version does not support this」と表示されて止まりました。curl –version の Features に HTTP2 があるかを先に見ておきます。
最後に、多重化を悪用した攻撃です。2023年10月に公表されたCVE-2023-44487は、要求の取り消しで多数のストリームを素早くリセットし、サーバーの資源を消費させるもので、2023年8〜10月に実際に悪用されたとNVDは記載しています。*10 同時ストリーム数の上限(nginxでは http2_max_concurrent_streams、既定128)を見直し、サーバーを修正版に上げておきます。*8
外部に委託するときに確認しておきたい点
Webサーバーやロードバランサーの構築・更改を外部に頼むときは、まず、どの区間でHTTP/2を使うかを構成図で示してもらいます。gRPCのように奥までHTTP/2が要る通信があるかで、製品や設定が変わるためです。
次に、確かめ方です。設定を入れたことではなく、ALPNで実際にh2が選ばれたことを検証の記録として残してもらいます。どの程度速くなるかは画面の作りや回線で変わるので、数字を約束させるより、切り替えの前後で同じ条件の測定をする計画があるかを見ます。
最後に、運用です。サーバープッシュのような廃止された機能に頼っていないか、同時ストリーム数などの上限を決めているか、脆弱性の情報を見てサーバーを更新する担当と手順が決まっているかを確かめておきます。
まとめ:HTTP/2で確かめておきたい3つの点
HTTP/2で確かめておきたい点は3つです。第一に、どの区間でHTTP/2を使っているかを把握し、ALPNで実際にh2が選ばれていることを確かめているか。第二に、多重化で並行の問題は減っても、TCPでの順番待ちは残ることを踏まえて期待値を決めているか。第三に、サーバープッシュやh2cのUpgradeのような使われなくなった機能に頼らず、同時ストリーム数の上限とサーバーの更新を運用に組み込んでいるかです。
よくある質問
HTTP/2を使うとアプリケーションの改修は必要ですか
メソッドやステータスコード、ヘッダーの意味は変わらないので、多くの場合はサーバー側の設定で済みます。ただし、Connectionヘッダーなど接続ごとのヘッダーを自分で付けている処理は見直します。
HTTP/2は暗号化が必須ですか
仕様上は暗号化しないh2cも定義されていますが、ブラウザーから使うのはTLS上のh2が前提です。TLS上で使う場合、RFC 9113はTLS 1.2以上を求めています。
HTTP/2とHTTP/3はどちらを選べばよいですか
HTTP/3はUDPの上のQUICで動き、TCPでの順番待ちを解消します。多くの構成では、HTTP/2を土台にしたうえでHTTP/3を追加で有効にし、使えない環境ではHTTP/2で通信する形になります。
Webサーバーと通信基盤の設計のご相談
元請(プライムベンダー)として、HTTP/2を前提にしたWebサーバーと通信基盤の設計・構築から、検証、保守・運用までご提案します。
Remoguとリラシクなら、Webサーバーやロードバランサーの構築・運用に加わるITエンジニアも探せます。
Remoguは、リモート前提で全国から即戦力のITプロ人材を調達するサービスです。リラシクは、扱う求人がすべてリモートワークのITエンジニア専門転職エージェントです。どちらもLASSICが運営しています。
出典
- *1 参考:IETF「RFC 9113: HTTP/2」(2022年6月)(https://www.rfc-editor.org/rfc/rfc9113)。出典:Abstract、1. Introduction、2. Protocol Overview、3.1〜3.3(h2・h2c)、4.1(フレームの形)、5.1.1(ストリーム識別子)、5.2(フロー制御)、5.3.2(優先度の非推奨)、6.5.2(SETTINGS)、8.2.2(接続ごとのヘッダー)、8.4(サーバープッシュ)、9.2(TLS)を参照(2026年10月確認)
- *2 参考:IETF「RFC 9110: HTTP Semantics」(2022年6月)(https://www.rfc-editor.org/rfc/rfc9110)。出典:Abstract(すべてのバージョンに共通する要素を定める)を参照(2026年10月確認)
- *3 参考:IETF「RFC 9112: HTTP/1.1」(2022年6月)(https://www.rfc-editor.org/rfc/rfc9112)。出典:Abstract、9.3.2 Pipelining(応答は要求を受け取った順)を参照(2026年10月確認)
- *4 参考:IETF「RFC 7541: HPACK: Header Compression for HTTP/2」(2015年5月)(https://www.rfc-editor.org/rfc/rfc7541)。出典:1.1 Overview(SPDYのDEFLATEとCRIME)、2.3(静的テーブルと動的テーブル)を参照(2026年10月確認)
- *5 参考:IETF「RFC 9218: Extensible Prioritization Scheme for HTTP」(2022年6月)(https://www.rfc-editor.org/rfc/rfc9218)。出典:4.1 Urgency、4.2 Incremental を参照(2026年10月確認)
- *6 参考:IETF「RFC 7301: Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension」(2014年7月)(https://www.rfc-editor.org/rfc/rfc7301)。出典:Abstract(TLSのハンドシェイクの中でアプリケーション層のプロトコルを決める拡張)を参照(2026年10月確認)
- *7 参考:Chrome for Developers「Remove HTTP/2 Server Push from Chrome」(2022年8月)(https://developer.chrome.com/blog/removing-push)。出典:Chrome 106での既定無効化、利用率1.25%と0.7%、代替の103 Early Hints を参照(2026年10月確認)
- *8 参考:nginx「Module ngx_http_v2_module」(nginx 公式ドキュメント)(https://nginx.org/en/docs/http/ngx_http_v2_module.html)。出典:Example Configuration、http2(1.25.1、既定off)、ALPNとOpenSSL 1.0.2の注意、http2_max_concurrent_streams(既定128)、http2_push(1.25.1で廃止、early_hints)を参照(2026年10月確認)
- *9 参考:curl「curl man page」(curl 公式ドキュメント)(https://curl.se/docs/manpage.html)。出典:–http2 の項(libcurlがHTTP/2に対応して組まれている必要)、-w の http_version を参照(2026年10月確認)
- *10 参考:NIST National Vulnerability Database「CVE-2023-44487」(https://nvd.nist.gov/vuln/detail/CVE-2023-44487)。出典:Description(ストリームの素早いリセットによるサービス妨害、2023年8〜10月の悪用)と公表日を参照(2026年10月確認)