この特集記事は2021年6月24日に発売されたWEB+DB PRESS Vol.123 に掲載された特集1「HTTP/3入門」 を再掲したものです。
先日2022年6月にHTTP/3を含むHTTP関連の仕様が正式なRFCとなりました。ここではRFCの正式リリースに伴い、いち早く変更点を抑え、囲みボックスを用いた加筆解説でわかりやすくお伝えしております。
特集のはじめに
HTTP(Hypertext Transfer Protocol )の最新版であるHTTP/3が登場しました。HTTP/3では、より安全で速い通信が行えます。本特集では、今までのHTTPにあった課題と、HTTP/3で課題をどのように解決し、改善が行われたかを解説します。
本章では、HTTPそのものと各バージョンをおさらいします。第2章では、HTTP/3が使うQUICというプロトコルを解説します。第3章では、HTTP/3のプロトコルの中身を深堀りします。第4章では、HTTP/3の実装やツール類を、実際の動作の様子もあわせて見ていきます。第5章では、HTTP/3の応用について紹介します。
HTTPとはそもそも何なのか?
そもそもHTTPとは何なのでしょうか。本節では、知っているようで知らないHTTPの役割と、バージョンについて整理します。
広く使用されているHTTP
インターネットが生活の中で広く利用されるようになりました。HTTPも多くの場所で利用されています。たとえば、Webページを閲覧する際やスマートフォンでアプリケーションを利用する際など、さまざまな通信でHTTPは利用されています。
Hypertext Transfer Protocolの略であるHTTPは、もともとはWebページを閲覧するためにハイパーテキストと呼ばれるデータを転送するためのものでした。その役割は今も変わりませんが、Webがリッチになるにつれ、多くのデータファイルの転送にも利用されるようになりました。
また、Webの表示以外にもさまざまなところで利用されるようになりました。現在では、外部サービスのAPI呼び出し、システム連携に用いるgRPC、OAuthといった認可プロトコル、サーバやミドルウェアの監視などにも利用されています。
HTTPとはプロトコルであり、セマンティクスである
HTTPはプロトコルの一つです。プロトコルとは、通信ルールのことです。ブラウザやWebサーバはHTTPという通信ルールにのっとりやりとりを行います。通信ルールにより、開発者が異なる多くのソフトウェアどうしがきちんと通信できます。
HTTPプロトコルでは、HTTPメッセージと呼ばれるメッセージを、通信を開始するクライアントと通信を受け付けるサーバの間でやりとりします。通信ルールには、そのメッセージのセマンティクスと、フォーマットが定義されています。
セマンティクスとは、メッセージの意味のことです。GET
やPOST
といったメソッドの意味や、user-agent
ヘッダといったヘッダの意味が定義されています。
フォーマットとは、送信するデータの形式のことです。HTTP/1.1ではテキスト形式ですが、HTTP/2以降ではバイナリ形式です。
HTTPのバージョンによってフォーマットは変わりますが、セマンティクスは変わりません。
HTTPのバージョンとセマンティクス
HTTPにはいくつかのバージョンがあります。現在はHTTP/1.1とHTTP/2が広く利用されており、HTTP/3も徐々に使われ始めています。HTTP/2以降、小数点以下のマイナーバージョンはなく、実装上マイナーバージョンを扱う場合は0とします。
HTTP/1.1以降のバージョンと、セマンティクスの歴史的遷移は図1 のとおりです。プロトコルの仕様は、標準化団体であるIETF(Internet Engineering Task Force )によってRFC(Request for Comments )として公開されます。HTTP/1.1の仕様はRFC 2068 、RFC 2616 を経て、RFC 7230 、RFC 7231 、RFC 7232 、RFC 7233 、RFC 7234 、RFC 7235 と改訂されてきました。HTTP/2、HTTP/3関連については後述します。
図1 HTTPの仕様の歴史
HTTPのセマンティクスは、これまではHTTP/1.1の仕様であるRFC 7230~RFC 7235の中で定義されていました。これらのRFCでは、セマンティクスとフォーマットがあわせて定義されていました。現在、これらの仕様を次の3つに分離する作業が進められています。
今後各HTTPバージョンの仕様からは、セマンティクスの定義としてHTTP Semanticsが参照されます。
この分離作業の中で、ヘッダやボディと呼ばれていた用語も整理が行われました。以降では、最新版の仕様草案の用語にのっとって説明していきます。普段使用している用語とは異なり馴染みづらいかもしれませんので注意してください。
補足情報:
2022年6月、正式にRFCとして出版されました。仕様の内容については、誌面での説明から変更はありません。
RFCは次のリンクから参照できます。
HTTPメッセージ
HTTPでは、HTTPメッセージをやりとりします。本節ではまず、HTTPメッセージの構成を説明します。そのあと、HTTPリクエストメッセージとHTTPレスポンスメッセージについて解説します。
HTTPメッセージの構成
セマンティクス上のHTTPメッセージの構成は図2 のとおりです。
図2 HTTPメッセージの構成
ヘッダセクション
コンテンツの前に来るヘッダフィールドが格納される領域。ヘッダフィールドは従来はヘッダと呼ばれていた
コンテンツ
データが格納される領域。従来はボディやペイロードと呼ばれていた
トレーラセクション
コンテンツのうしろにくるトレーラフィールドが格納される領域。トレーラフィールドも従来はヘッダと呼ばれていた
これらの呼称はHTTP/2標準化後に整理が行われたため、ヘッダ圧縮など一部の用語で、フィールドと呼ぶべきところがヘッダと呼称される場合があります。本特集では、仕様上ヘッダと表記される用語はヘッダと記述します。
以降では、ヘッダセクションとトレーラセクションに格納されるHTTPフィールドについてと、コンテンツについて順に説明します。
HTTPフィールド ── メッセージのメタデータ
HTTPメッセージには、そのメッセージのメタデータであるHTTPフィールド(以下、フィールド)が付きます。
ヘッダセクションにあるフィールドがヘッダフィールド(以下、ヘッダ) 、トレーラセクションにあるフィールドがトレーラフィールド(以下、トレーラ)です。後者はあまり知られていない機能ですが、HTTPではコンテンツを送ったあとにトレーラを送れます。両者を区別しないとき、単にフィールドと呼びます。
フィールドは、HTTPメッセージやコンテンツに関する情報を伝達する、キーとバリューのデータです(図3 ) 。キーをフィールド名、バリューをフィールド値と呼びます。セマンティクス上は区切り文字は定義されていませんが、HTTP/1.1のように:
で区切ったhost: example.com
といった表現をフィールドラインとも呼びます。
図3 HTTPフィールド
コンテンツ
クライアントもしくはサーバから相手にデータを届ける際は、コンテンツに格納されます。たとえば、サーバがクライアントの要求に対して送り返すWebページのデータや、クライアントからサーバにアップロードするファイルのデータが格納されます。
HTTPリクエストメッセージ ── クライアントの要求
HTTPメッセージのうち、クライアントからサーバに送信されるメッセージをHTTPリクエストメッセージ(以下、リクエスト)と呼びます。リクエストと呼ぶように、クライアントからの要求をサーバに伝えます。たとえば、特定のファイルを送るように要求します。また、ファイルをアップロードする際にも使用されます。HTTPの通信は、リクエストが送信されることで始まります。
以降では、HTTP/1.1とHTTP/2でどのようなメッセージが送信されているかを確認します。HTTP/3については第3章で説明します。
HTTP/1.1の場合
まずはHTTP/1.1のリクエストの例を見てみましょう。これは、curl(バージョン7.68.0)コマンドでhttps://example.com
のページを要求した際に送信されたものです。
HTTP/1.1におけるリクエスト
GET / HTTP/1.1
Host: example.com
User-Agent: curl/7.68.0
Accept: */*
HTTP/1.1では、改行をもって1行ごとに区切られており、1行目にリクエストラインと呼ばれる行が存在します。各文字列の意味は次のとおりです。
GET
HTTPメソッド
/
パス
HTTP/1.1
バージョン
2行目からはリクエストヘッダフィールド(以下、リクエストヘッダ)が続きます。リクエストヘッダにはさまざまなものが定義されており、ブラウザは多くのヘッダを送信しています。
リクエストヘッダのあとに空行(改行2つ)を挟んでコンテンツが続きます。GET
リクエストはコンテンツを含まないため、上記は空行(改行2つ)で終わっています。POST
やPUT
といったファイルをアップロードするようなリクエストでは、アップロードしたいファイルがコンテンツとして格納されます。
HTTP/2の場合
次にHTTP/2の例を見てみましょう。詳しくは後述しますが、HTTP/2がやりとりするデータはフレームと呼ばれるバイナリ形式ですので、Wireshark(バージョン3.4.3)を使って送っているメッセージをパースします(図4 ) 。
図4 HTTP/2のリクエスト
リクエストラインはありません。HTTP/1.1のリクエストラインにあったHTTPメソッドやパスは、ヘッダと同様に処理できるように、ヘッダ名がセミコロンで始まる擬似ヘッダで表されます。リクエストラインにあったバージョンは送信されません。そのほかのリクエストヘッダは、HTTP/1.1のころと変わらずヘッダ名とヘッダ値で表現されます。
続けて、バイナリ形式で確保された領域でコンテンツのデータが送信されます。HTTP/1.1とは異なり明確にパースできるしくみになっており、改行といった区切りは持ちません。
HTTPレスポンスメッセージ ── サーバの応答
HTTPメッセージのうち、サーバからクライアントに送信されるHTTPメッセージをHTTPレスポンスメッセージ(以下、レスポンス)と呼びます。レスポンスは、クライアントからのリクエストへの応答です。サーバがレスポンスを送る際は、必ず先にリクエストが行われている必要があります。
以降では、HTTP/1.1とHTTP/2でどのようなメッセージが送信されているかを確認します。HTTP/3については第3章で説明します。
HTTP/1.1の場合
まずはHTTP/1.1のレスポンスの例を見てみましょう。これは、先ほどcurlコマンドでhttps://example.com
のページを要求した際に応答として送信されたものです。
HTTP/1.1におけるレスポンス
HTTP/1.1 200 OK
Accept-Ranges: bytes
Age: 234274
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
(レスポンスヘッダ省略)
コンテンツデータ
HTTP/1.1では、改行をもって1行ごとに区切られており、1行目にステータスラインと呼ばれる行が存在します。各文字列の意味は次のとおりです。
HTTP/1.1
バージョン
200
ステータスコード
OK
リーズンフレーズ
2行目からはレスポンスヘッダフィールド(以下、レスポンスヘッダ)が続きます。レスポンスヘッダもさまざまなものが定義されており、キャッシュの制御やセキュリティに関する指示などさまざまな用途で利用されます。
レスポンスヘッダのあとに空行(改行2つ)を挟んでコンテンツが続きます。
HTTP/2の場合
HTTP/2の場合、リクエストと同様にレスポンスもバイナリ形式で表現されます。
レスポンスにステータスラインはありません。HTTP/1.1のステータスラインにあったステータスコードは、擬似ヘッダとして格納されます。ステータスラインにあったバージョンとリーズンフレーズは送信されません。そのほかのレスポンスヘッダは、HTTP/1.1のころと変わらずヘッダ名とヘッダ値で表現されます。
そのあと、リクエストと同じようにコンテンツが送信されます。
HTTP/2のおさらい
本節では、HTTP/2についておさらいします。
HTTP/2は、HTTPメッセージをより効率良くやりとりするための仕様です。Googleが考案したSPDYというプロトコルをもとにし、2015年にRFC 7540 として標準化されました。あわせて、ヘッダ圧縮のしくみであるHPACKもRFC 7541 として標準化されています。
以降では、HTTP/2が解決したかった問題と、解決方法、そして現在議論されているHTTP/2の改訂版について解説します。
HTTP/1.1が抱えていた問題
2010年ごろより、Webがより発達し、各ページの見た目や振る舞いがよりリッチになっていきました。それに伴いWebページの表示に必要なファイル数は多くなり、ブラウザとサーバでやりとりされる通信の数も増えました。そういった中で、HTTP/1.1が抱える問題に直面します。
Head-of-Line-Blocking問題 ── 通信の待ち状態の発生
問題の一つが、通信の待ち状態を生むHead-of-Line-Blockingです。
HTTP/1.1には、1回の接続で連続してリクエストを送信するKeep-Aliveという機能があります。これにより、多くのリクエストを一度に送信できます。しかし、Keep-Aliveではリクエストされた順番でレスポンスを返す必要があります。リクエストを1、2、3、4と順番に送った場合、レスポンスも1、2、3、4と順番に返す必要があります。
たとえば、2のレスポンスの生成に時間がかかるとします。そうすると、仮に3や4のレスポンスを返す準備ができても送信できません。これが、前の処理が止まることで後続の処理が待たされるHead-of-Line-Blocking問題です(図5 ) 。
図5 HTTP/1.1のHead-of-Line-Blocking問題
TCPコネクションの確立と切断を繰り返す
Keep-Aliveを使う代わりに、下位層で利用しているTCP(Transmission Control Protocol )のコネクションであるTCPコネクションを複数使ってリクエストを送り、TCPコネクションの確立と切断をつど行う方法もありました。これは、TCPコネクションの確立に時間がかるうえ、帯域の使い方としても非効率です。
HTTP/2による問題の解消
HTTP/2は、HTTP/1.1にあった問題をどのように解消したのかを見ていきましょう。
メッセージの並列化
HTTP/2では、1つのTCPコネクション上で複数のHTTPメッセージを並列的に多重化してやりとりします。やりとりのイメージは図6 のようになります。リクエストとレスポンスの1つのペアは、ストリームという単位で管理されます。ストリームはあくまで管理の単位です。実際にデータをネットワーク上で送信する際に、並列に送ることはできません。
図6 HTTP/2の並列性
HTTP/2では、各HTTPメッセージを細切れにして直列的に送信することで、あたかもHTTPメッセージが並列的に送信されているかのようにしています。このときに使うのがフレームです。1つのHTTPメッセージは、複数のフレームに分割されて送受信されます(図7 ) 。
図7 HTTP/2のフレーム
フレームは、バイナリ形式で表現されています。フレーム内に格納される数値や文字列といった情報は、ビット単位で情報を格納する位置が決められており、そこに仕様で決められた2進数データとして格納されます。詳細は割愛しますが、フレームは用途ごとに10タイプ定義されています。HTTPメッセージを運ぶ以外に、通信を切断する際に使用するフレームなどが定義されています。
このしくみにより、リクエストとレスポンスが紐付( ひもづ ) き、リクエストを送った順番でレスポンスを返す必要がなくなります。つまり、Head-of-Line-Blocking問題が解消されます。
1つのTCPコネクションを長く使い回す
先述したようにHTTP/2では1つのTCPコネクションを長く使い回しますので、確立と切断を繰り返す必要はなくなりました。
そのほかの機能
HTTP/2にはほかにも、ウィンドウ制御、ヘッダ圧縮、サーバプッシュ、優先度制御、エラーハンドリングといった機能があります。
ウィンドウ制御は、受信側の記憶領域であるバッファをあふれさせないように、送信するデータ量を制御するしくみです。
ヘッダ圧縮、サーバプッシュ、優先度制御、エラーハンドリングについては、同様のしくみがHTTP/3にもあるので第3章で説明します。
HTTP/2の仕様改訂の動き
HTTP/2を改善するために、改訂版を出そうという動きが出てきています。この仕様はHTTP/2 bis と呼ばれ、草案に含める変更を議論中です。HTTP Semantics仕様への参照や、使われていない機能の削除が検討されています。
補足情報:
草案の段階ではHTTP/2 bisと呼ばれていましたが、2022年6月にHTTP/2のRFCとして出版されました。正式なRFCとなったためHTTP/2 bisではなく、こちらがHTTP/2の仕様ということになります。
RFC 7540からの変更点として次の項目が挙げられます。
RFC 9110で定義される用語に準拠
RFC 7540で定義される優先度制御の廃止
HTTP/1.1から通信をHTTP/2に切り替えるアップグレードのしくみを廃止
RFCは次のリンクから参照できます。
HTTP/3の基本
さて、いよいよHTTP/3についてです。本節では、HTTP/3の概要と、標準化や実装の状況を解説します。HTTP/3の詳細は、第3章で説明します。
HTTP/2は問題を抱えていたのか
HTTP/2の利用が進む中で、HTTPをより速くするにはどうすればよいか、問題がどこにあるかに興味が持たれるようになりました。HTTP/2に問題がないわけではありませんが、大きな問題として注目されたのは、HTTP/2が下位層で利用しているTCPというプロトコルでした。
TCPでは、送信者がパケットを送信した順番どおりに、受信者はパケットを処理する必要があります。そのため、パケットロスが発生した場合は、送りなおしてもらう必要があります。パケットの順番の入れ替わりが発生した場合は、もとの順番に戻す必要があります。パケットロスやパケットの順番の入れ替わりが解消されるまでは、処理は待ちとなります。
図6を例に考えてみましょう。先に送信された上のストリームのデータを運ぶパケットにパケットロスなどの問題が発生した場合、後続の下のストリームのデータを運ぶパケットを受信できても、パケットロスなどの問題が解消されるまで、ブラウザは処理を進めることができません。つまりHTTP/2では、ストリームは別のストリームの影響を受けます。そのため、1つのパケットロスや順番の入れ替わりにより、TCPコネクション上のすべてのHTTPメッセージのやりとりまで止まってしまいます。これが、TCPのHead-of-Line-Blocking問題です。
HTTP/3による問題の解消
問題を解決するために、HTTP/3では下位層にTCPではなく新しく開発されたQUICというプロトコルを使います。QUICは、パケットロスやパケットの順番の入れ替わりが起きても、受信者が受け取った順番にデータを処理できます。この利点を活かすために、HTTP/3は極力受け取った順番にデータを処理するようになっています。QUICの詳細は、第2章で解説します。
先ほどと同様のケースを考えてみましょう。HTTP/3では、ストリームは別のストリームの影響を受けません。そのため、あるストリームでパケットロスなどの問題が発生しても、やりとりが止まるなどの影響を受けるのはそのストリームだけです。別のストリームは、影響を受けず処理を進めることができます。そのためHead-of-Line-Blocking問題は発生せず、Webページを速く表示できます。
標準化の道のり
本項ではHTTP/3の標準化の道のりを説明します。
2013年~2016年:GoogleによるGoogle QUICの実験
HTTP/3の最初は、Googleが2013年ごろよりGoogle ChromeおよびGoogleのサービスで実験していたQUIC(以下、Google QUIC)にさかのぼります。Google QUICは、現在のQUICとは多くの点で異なり、パケットロスの再送処理や暗号化といったトランスポートプロトコルとしての機能と、その上に乗るアプリケーションプロトコルであるHTTPの機能をひとまとめにしたプロトコルでした。
2015年、GoogleはGoogle QUICの成果をIETFの非公式ミーティングで発表しました。これにより、Google QUICは多くの興味を引きました。
なお、Google QUICは過渡期のものであり、現在ではGoogleもQUICを利用しています。
2016年~2018年:IETFによるHTTP over QUICの標準化
IETFの取り組みはワーキンググループという単位で議論されます。QUICの標準化を進めるため、2016年11月にQUICワーキンググループが設立されました。その際、QUICはトランスポートプロトコルとして標準化が進められることになり、アプリケーションプロトコルとは分離されました。
アプリケーションプロトコルとしてはまずHTTPにフォーカスすることになり、仕様の草案は、HTTP over QUIC と名付けられました。
なお、Google QUICは「Quick UDP Internet Connections」の略語でしたが、現在のQUICは「QUIC is a name, not an acronym」として、何かの略語ではないとされています。
2018年~:IETFによるHTTP/3への改称と標準化
2018年11月に行われたIETFミーティングにて、HTTP over QUICをHTTP/3と改称する議論が行われました。このミーティングで出た意見として、「 Google QUICと明確に区別する」「 HTTP/2 over QUICではないことを強調する」といったものがありました。議論の結果、2018年12月に提出された草案にてHTTP/3に改称されました。
執筆時点(2021年5月)では、QUICの仕様はRFCになっています。これについては第2章で解説します。HTTP/3の仕様は草案の34版 が出ており、RFCの発行を待つばかりという状況です。ここから変更はほぼないでしょう。また、HTTP/3が利用するヘッダ圧縮のしくみであるQPACK も合わせて標準化が進められており、HTTP/3と同じタイミングでRFCになる予定です。
補足情報:
2022年6月にRFCとして出版されました。誌面掲載時は、QPACKは「QPACK: Header Compression for HTTP/3」という仕様名でしたが、セマンティクスの用語に合わせて「QPACK: Field Compression for HTTP/3」に変更されています。仕様の内容については、誌面での説明から変更はありません。
RFCは次のリンクから参照できます。
実装状況
HTTP/3の実装状況を説明します。なお、執筆時点ではRFCが出ていないため、草案仕様準拠の対応になっています。
ブラウザは、Chrome、Firefox、Safariが対応しています。Webサーバは、たとえばnginxで実装が進められており、正式版はリリースされてはいませんが、開発版ではHTTP/3が使えます。CDN(Content Delivery Network )は、FastlyやCloudflareで対応しています。
まとめ
本章では、HTTPとは何かや、HTTPのこれまでを整理しました。HTTPには複数のバージョンがあり、HTTP/2では1つのTCPコネクション上でHTTPメッセージを並列的にやりとりできるようになり、HTTP/3では新しくQUICと呼ばれるプロトコルを利用するようになりました。