HTTP/2の「握手」の裏側:ALPNがもたらす静かなる革命
ネットワークエンジニアとして現場に立っていると、若手から「HTTP/2って結局何が速いの?」と聞かれることがある。ストリームの多重化やHPACKによるヘッダー圧縮も重要だが、真に評価すべきは、「いかにしてHTTP/1.1の呪縛を断ち切り、スムーズに次世代プロトコルへ移行したか」というその接続戦略にある。
今回は、その門番である「ALPN」の仕組みを深掘りしていこう。現場でパケットキャプチャを眺める際に、この握手のシーケンスが見えているかどうかで、トラブルシューティングの解像度が劇的に変わるはずだ。
—
1. なぜALPNが必要だったのか:HTTP/1.1との「見えない壁」
HTTP/1.1からHTTP/2へ切り替える際、最大の問題は「相手がHTTP/2を喋れるか分からない」という点だ。もし適当にHTTP/2のバイナリフレームを投げつけて、相手がHTTP/1.1のサーバーだったらどうなるか? サーバーは不正なリクエストとして即座にコネクションを切断するだろう。
かつてHTTP/1.1で使われていた「Upgradeヘッダー」を使ったネゴシエーション(Cleartext Upgrade)は、非セキュアな通信が前提であり、現代のWebの常識である「HTTPS(TLS)必須」の世界では力不足だった。
ここで登場するのが ALPN (Application-Layer Protocol Negotiation) だ。
—
2. ALPNのシーケンス:TLSハンドシェイクという「特等席」
ALPNの美しさは、TLSハンドシェイクという、プロトコルが確定する前の「最も神聖な儀式」の中に交渉をねじ込んだことにある。
通信の流れは以下の通りだ。
1. Client Hello: クライアントはTLSのハンドシェイクを開始する際、`ALPN`という拡張フィールドを添える。ここに「俺は `h2` も `http/1.1` も喋れるぞ」というリストを載せる。
2. Server Hello: サーバーは送られてきたリストを確認し、自分が対応しているプロトコルの中で最も優先度の高いもの(通常は `h2`)を選び、同じく`ALPN`拡張で返答する。
3. ハンドシェイク完了: この時点で、TLSの暗号化トンネルが構築されると同時に、その中でHTTP/2を使うことが合意される。
この方式なら、余計なラウンドトリップ(往復通信)を発生させることなく、TLSの接続とプロトコルの確定が同時に完了する。まさに「効率の極み」だ。
—
3. 実践:ALPNを確認するためのデバッグ手法
現場で「なぜかHTTP/2にならない」というトラブルはよくある。まずは自分の環境が正しくALPNでネゴシエーションできているか、`curl`を使って確認するのが定石だ。
curlでプロトコルの詳細を覗く
-v: 詳細表示, –http2: HTTP/2での接続を強制するオプションではないが、
ALPNでh2が選択されたかを確認するのに適している
curl -vI https://www.google.com 2>&1 | grep “ALPN”
出力結果に `ALPN, server accepted to use h2` とあれば、その通信は正しくHTTP/2の恩恵を受けている。もしここで `http/1.1` にフォールバックしていたら、サーバー側の設定(Nginxやロードバランサー)がHTTP/2をサポートしていないか、証明書の不備を疑うべきだ。
—
4. サーバー側(Nginx)の設定Tips
インフラエンジニアとして、NginxでHTTP/2を有効にする設定はシンプルだが、落とし穴もある。
server {
listen 443 ssl http2; # 「http2」と書くだけでALPNの設定は自動化される
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# HTTP/2が有効か確認するためのログフォーマット
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘$http_user_agent “$http2″‘; # $http2変数でプロトコルを表示
}
注意点: OpenSSLのバージョンが古いとALPNをサポートしていないことがある。最近のOSなら心配無用だが、古いオンプレ環境を保守している場合は `openssl version` で確認を怠らないこと。
—
5. PythonでALPNを叩く:`h2`ライブラリの活用
もしあなたがAPIクライアントを自作しているなら、`requests`ではなく `httpx` や `hyper-h2` を使うことになるだろう。以下は `httpx` を使ったシンプルな接続チェックだ。
import httpx
httpxはデフォルトでHTTP/2をサポートしている
with httpx.Client(http2=True) as client:
response = client.get(“https://www.google.com”)
# どのプロトコルが選ばれたかを表示
print(f”Negotiated Protocol: {response.http_version}”)
# 結果が ‘HTTP/2’ と出ればOK
—
最後に:ネットワークエンジニアとしての視点
HTTP/2のALPNを理解することは、単なるプロトコルの知識向上ではない。それは「通信の開始時に何が起きているか」を可視化する力を養うということだ。
パケットキャプチャを開き、TLSハンドシェイクの `Client Hello` パケットを見てほしい。そこに刻まれたプロトコルのリストは、クライアントの「意思」であり、`Server Hello` で選ばれたプロトコルは、サーバーとの「合意」だ。
Web APIの設計においても、単に「HTTP/2対応」と謳うだけでなく、このようなネゴシエーションの仕組みを理解しているエンジニアであれば、将来のHTTP/3(QUIC)への移行にも迷わず対応できるはずだ。
プロトコルは生き物だ。その呼吸を、ぜひパケットを通して感じてみてほしい。
コメント