この文書は「HTTP/2 Frequently Asked Questions」の日本語訳です。

原文の最新版は、この日本語訳が参照した版から更新されている可能性があります。
この日本語訳は参考情報であり、正式な文書ではないことにも注意してください。また、翻訳において生じた誤りが含まれる可能性があるため、必ず原文もあわせて参照することを推奨します。

一般的な質問

なぜ HTTP を見直すのですか?

HTTP/1.1 は15年以上にわたってうまく Web を提供してきましたが、時代遅れのものになりつつあります。

Web ページの読み込みにはこれまで以上に多くのリソースが消費され (HTTP Archive のページサイズ統計を参照)、それらのリソースの全てを効率的に読み込むのは困難です。なぜならば、HTTP では実質的に TCP 接続あたり1つのリクエストしか送信できないためです。

従来から、ブラウザーはリクエストを並列に発行するために複数の TCP 接続を使用してきました。しかしこれにも限界があります。非常に多くの接続が使用された場合、2つの逆効果 (TCP 輻輳制御は事実上否定され、パフォーマンスとネットワークに影響する輻輳に至ります) と、根本的な不公平 (ブラウザーはより多くのネットワークリソースを必要とします) を生んでしまいます。

それと同時に、多数のリクエストは多くの冗長なデータを "転送している" ことも意味します。

これらの要因はいずれも、HTTP/1.1 リクエストには、それに関連する多くのオーバーヘッドがあることを意味します。非常に多くのリクエストが行なわれた場合、パフォーマンスが低下します。

このことは、スプライト化やインライン化、ドメインシャーディング、ファイル結合などを行うことがベストプラクティスと考えられる場所に、業界を導いてきました。そのようなハックは、プロトコルそのものに根本的な問題があることを示しており、使用されるとより多くの問題を引き起こしてしまうのです。

誰が HTTP/2 を作ったのですか?

HTTP/2 は、IETF で HTTP プロトコルを整備している HTTPbis ワーキンググループにより開発されました。このワーキンググループは、HTTP の実装者、ユーザー、ネットワークオペレーター、そして HTTP エキスパートで構成されています。

我々のメーリングリストは W3C のサイトでホストされていますが、W3C の活動ではないことに注意してください。しかしながら、Tim Berners-Lee と W3C TAG が WG の進捗状況を更新しています。

非常に多くの人々がこの活動に貢献しており、活発な参加者には、Firefox、Chrome、Twitter、Microsoft HTTP スタック、Curl や Akamai といった "巨大" プロジェクトのエンジニアたちだけでなく、Python や Ruby、Node.js などの言語の HTTP 実装者も含まれています。

IETF への参加についてより詳しく知りたい場合は、IETF の Tao を参照してください。また、GitHub の貢献者グラフでは誰が仕様に貢献しているのかを、我々の実装リストでは誰が実装しているのかをそれぞれ確認することができます。

SPDY との関係は?

SPDY が HTTP/1.x に対して明らかな改善を示し、(MozillaとNginxのような) 実装者によりその勢いが増したことが明らかになった時、HTTP/2 は初めて議論されました。

提案の募集とその選定プロセスを経て、SPDY/2 は HTTP/2 の基礎に選ばれました。それ以来、ワーキンググループでの議論や実装者からのフィードバックに基づき、様々な変更が行われました。

このプロセスを通じて、Mike Belshe、Roberto Peon の2人を含む SPDY の主要な開発者は HTTP/2 の開発にも関わってきました。実際のところ、SPDY/4 の改訂版はまだリリースされていませんが、これは HTTP/2 に基づいています。SPDY コミュニティは SPDY/4 を HTTP/2 の競争相手としてではなく、HTTP/x にフィードバックするためのさらなる実験方法としてとらえています。

HTTP/2.0 ではなく HTTP/2 なのですか?

ワーキンググループは、HTTP/1.x では多くの混乱を招いたため、マイナーバージョン (".0") を外すことに決めました。

言い換えると、HTTP バージョンは機能や "マーケティング" 上のものではなく、プロトコルの互換性だけを表します。

HTTP/1.x との主な違いは何ですか?

HTTP/2 では主に:

なぜ HTTP/2 はバイナリを使用するのですか?

バイナリプロトコルは、小さな容量で転送でき、より効率的に解析できます。そして最も重要なのは HTTP/1.x のようなテキストプロトコルと比較して、間違いを少なくできることです。なぜなら、テキストプロトコルは、空白の処理や大文字と小文字の区別、改行コード、空白のリンクといったものに対応する多くのアフォーダンスを持っているからです。

例えば、HTTP/1.1 では異なる4つのメッセージの解析方法が定義されていますが、HTTP/2 においては1つだけです。

HTTP/2 が telnet を通じて使用できないのは事実ですが、我々はすでに Wirshark プラグインなどのいくつかのツールをサポートしています。

なぜ HTTP/2 は多重化するのですか?

HTTP/1.x には、接続上で1度に処理できるリクエストは実質的に1つだけになる "head-of-line blocking" と呼ばれる問題がありました。

HTTP/1.1 は パイプラインにより改善を試みましたが、この問題を完全には解決しませんでした (巨大なレスポンスや遅いレスポンスが、それ以降の他のレスポンスをブロックすることができてしまいます)。加えて、パイプラインは多くの中継機器やサーバーが正しく処理をしないため、デプロイすることが非常に難しいことが分かっています。

このことは、リクエストをどのオリジンへの接続にいつ割り当てるかを決定するために、クライアントに様々な発見的手法 (その多くは推測) の使用を強制します。ページは使用可能な接続数の10倍 (またはそれ以上) を読み込むことが一般的であるため、これは著しくパフォーマンスに影響し、多くの場合ブロックされたリクエストの "ウォーターフォール" を生み出します。

多重化は、複数のリクエストやレスポンスのメッセージを同時に転送することを可能にし、このような問題に取り組みます。転送中に別のメッセージの一部が混在することも可能になります。

同様に、クライアントはページを読み込むために、オリジンごとに1個の接続だけを使用すればよいことになります。

なぜ 1 個の TCP 接続しか使わないのですか?

現在ブラウザーは 1 ドメインあたり 4 から 8 個の接続を使用しています。多くのサイトでは複数のドメインを使用しているので、1 ページをロードすると実に 30 個を超える接続を使用することになります。

同時に多くの接続を開くアプリケーションは TCP の設計上の多くの前提を崩しているのです。各接続において応答データが一挙に流れ出すと、途中経路上のネットワークのバッファーが溢れ、輻輳が発生しパケット再送が起こる危険性があります。

さらに、公正を欠くような過度の接続はネットワーク資源を独占することになり、紳士的に振る舞う他のアプリケーション (例: VoIP) から資源を "盗んで" いることになるのです。

サーバープッシュの利点は何ですか ?

ブラウザーがページを要求するとサーバーは HTML を応答として送信しますが、サーバーが HTML に埋め込まれている JavaScript、画像、CSS のアセットを送信するには、ブラウザーが HTML を解析し、それらのリクエストを送信するまで待たなければなりません。

サーバープッシュは、クライアントが必要とするであろうと思われる応答をサーバーが判断し "プッシュ" することでラウンドトリップを回避します。

なぜヘッダー圧縮が必要なのですか ?

Mozilla の Patrick McManus は平均ページロード時間におけるヘッダーの影響度を計算し、ヘッダー圧縮の必要性を強く示してくれました。

1 ページが約 80 個のアセット (これは現在の Web においては比較的控えめな数値です) で構成されており、各リクエストが 1400 バイトのヘッダー (Cookie や Referer 等の影響により、この数値は珍しくありません) を持つと仮定します。この場合、ヘッダーの送出に 7-8 ラウンドトリップが必要です。これは応答時間を含めていないことに注意してください。クライアントからヘッダーを送出する時だけでこれほど必要なのです。

これは TCP の スロースタート メカニズムが原因なのです。このメカニズムは、確認応答が得られたパケットの数を元にパケット送信のペースを調整するのです。 これにより、新しい接続の最初の数ラウンドトリップにおいて送信できるパケットの数は実質的に制限されることになります。

これに対し、比較的緩い圧縮であってもヘッダーに施せば、これらリクエストを一つのラウンドトリップで送出できます。うまく行けばひとつのパケットに収めることができます。

この (訳注: ラウンドトリップの) オーバーヘッドは大きいものです。良いコンディションにおいてもラウンドトリップの遅延が数百ミリ秒に達するのが普通であるモバイルクライアントにおいては特にそうです。

なぜ HPACK を使うのですか?

SPDY/2 では、ヘッダー圧縮のために送信と受信それぞれに 1 つの GZIP コンテキストを使用することを提案しました。これは実装が簡単なだけでなく、効率的でした。

しかしその後、暗号化されたデータ内での (GZIPのような) ストリーム圧縮の使用に対する大規模な攻撃手法が報告されました。それが CRIME です。

CRIME は、暗号化ストリームにデータを挿入できる攻撃者であれば、平文を "探り出し"、それを復元することができます。Web においては、JavaScript がこれを可能にします。TLS で保護された HTTP リソースに対して、CRIME を使用してクッキーや認証トークンを復元するデモも存在します。

このような結果から、我々は GZIP 圧縮を使用できませんでした。しかし、ユースケースに適しているだけでなく、安全に使用できる他のアルゴリズムは見つかりません。そこで、我々は新たに粒度の粗いヘッダー向けの圧縮方式を開発しました。ほとんどの場合、HTTP ヘッダーはメッセージ間で変更されないため、この新しい圧縮方式は合理的な圧縮効率をもたらし、より安全であるといえます。

HTTP/2 はクッキー (またはその他のヘッダー) を改善しますか?

HTTP/2 の活動は HTTP のセマンティクスを変更せず、"転送される" もの、つまり HTTP ヘッダーやメソッドといった転送プロトコルの改訂作業に注力しました。

HTTP が広く使われていることがその理由です。もし我々が新しい状態機構の導入(議論された一例) やコアの機能を変更 (ありがたいことに、これはまだ提案されていません) するためにこの HTTP のバージョンを使用してしまうと、それは新しいプロトコルが既存の Web と非互換になってしまうことを意味します。

特に、我々は HTTP/1 から HTTP/2 に変換し、情報を失うことなくそれを元に戻せることを目指しています。もし我々がヘッダーの "掃除" を始めて (HTTP ヘッダーがとても複雑になっていることをほとんど認めて) しまうと、既存の Web の多くに互換性の問題が生じることになります。

これは、単に新しいプロトコルの採用に対する対立が生むことになります。

このように、ワーキンググループには HTTP/2 だけでなく HTTP の全てに対する責任があります。我々は既存の Web と下位互換でさえあれば、バージョンに依存する新しい機構に取り組むことができます。

非ブラウザーにおける HTTP の使用についてはどうなりますか?

現在 HTTP を使用している非ブラウザーアプリケーションは HTTP/2 を使用することができると考えています。

早い段階において得られたフィードバックから、HTTP/2 は HTTP "APIs" において良い性能特性を持つことが示されました。なぜなら API はリクエストのオーバーヘッドを考慮する必要がなくなるからです。

とはいいつつも、やはり主となる性能向上はブラウザーによるユースケースであると我々は考えています。なぜならそれこそがこのプロトコルの基本的なユースケースであるからです。

我々の憲章は以下のように述べています:

出来上がる仕様は、ありふれた既存の HTTP のデプロイメントについてこれらの目標を達成する予定です。
特に Web ブラウジング (デスクトップとモバイル)、非ブラウザー ("HTTP APIs")、
Web サービス (規模は大小あります)、中継サーバー (プロキシー、企業のファイアーウォール、
"リバース" プロキシー、CDN) が対象となります。
また、現在そして未来における HTTP/1.x に対するセマンティックな拡張 (例: ヘッダー、
メソッド、ステータスコード、キャッシュディレクティブ) は新しいプロトコルにおいてサポートされるべきです。

HTTP では未定義である振る舞いに依存しているユースケースは対象外であることに注意してください
(例: タイムアウトやクライアントアフィニティといった接続の状態、"透過" プロキシー)。
最終的な仕様はこれらの使用を無効にする可能性があります。

HTTP/2 では暗号化が必須なのですか?

いいえ。長い議論の末、ワーキンググループは新しいプロトコルにおける暗号化 (例: TLS) を必須にすることについてコンセンサスを得ることができませんでした。

しかし、いくつかの実装 (訳注: Mozilla Firefox、Chromium) の開発者は HTTP/2 を暗号化された通信路上でのみサポートすると発言しています。

HTTP/2 はセキュリティ向上のために何を行うのですか?

現時点で HTTP/2 は要求する TLS のプロファイルを定義しています。この定義には、バージョンや Cipher Suite、使用する拡張が含まれています。

詳しくは仕様を参照してください。

TLS を HTTP:// URL に使用するような追加の機構 ("日和見暗号" と呼ばれます) についての議論もあります。Issue #315 を参照してください。

HTTP/2 を今から使うことはできますか?

ブラウザにおいては、HTTP/2 は Firefox と Chrome の最新版でサポートされています。Blink ベースの他のブラウザ (例: Opera や Yandex Browser) も HTTP/2 をサポートするでしょう。Microsoft と Apple は、どちらも将来のリリースにおいて HTTP/2 をサポートする予定があることを告知しています。

いくつかのサーバー (Akamai のベータサポートや、GoogleTwitter のサイトを含む) が提供されており、デプロイしてのテストが可能なオープンソースの実装も多数あります。

詳しくは実装リストを参照してください。

HTTP/2 は HTTP/1.x を置き換えますか?

HTTP/1.x の一般的な用途で HTTP/2 を使用でき、その成果を見ることがワーキンググループの目標です。とは言うものの、我々は、人々がプロキシーやサーバーをデプロイする方法や、世界に対して移行を強制することはできません。HTTP/1.x はまだしばらくの間使用される可能性は高いと言えます。

HTTP/3 はありますか?

HTTP/2 で導入されたネゴシエーション機構がうまく動作すれば、以前と比べてはるかに簡単に HTTP の新しいバージョンをサポートすることが可能になるはずです。

実装上の質問

HEADERS フレームの延長 (CONTINUATION) に関するルールが存在するのはなぜですか ?

フレームの延長が存在する理由は、ヘッダーフィールド (例: Set-Cookie) の長さが 16KiB - 1 を超える可能性があり、その場合一つのフレームに収めることができないからです。実装の上で最も間違いが少ないような解決方法を模索したところ、全ヘッダーデータが連続したフレームで送信されなければならないというルールに落ち着きました。これはデコード時のバッファー管理も容易になるというメリットもあります。

HPACK の状態を保持する上で必要なメモリ量の下限と上限は何ですか?

受信側が HPACK で使用するメモリ量を常に制御します。下限値は 0 です。上限値は SETTINGS フレームで表現できる最大の整数型の値、現在では 2^32 - 1 です。

HPACKの状態を保持しないようにするにはどうすればよいですか?

SETTINGS フレームで状態サイズ (SETTINGS_HEADER_TABLE_SIZE) を 0 にして送信し、ACK フラグ付きの SETTINGS を受信するまですべてのストリームに RST_STREAM フレームを送信します。

なぜ圧縮コンテキストとフローコントロールは単一なのですか?

シンプルにするためです。

オリジナルの提案ではストリームはグループを構成でき、その中ではフローコントロールなどのコンテキストを共有することも可能でした。これはプロキシーにとっては有益である (そしてそれを使うユーザーにとっても有益でしょう) 反面、かなり複雑度が増すことになります。そこで我々は最もシンプルな方式からはじめることにして、それが苦痛であるか見極め、その苦痛 (もしあればですが) を未来のプロトコルリビジョン (訳注: HTTP/3?) で解決することにしました。

HPACK の EOS シンボルはなぜ存在するのですか?

HPACK のハフマン符号化は、CPU を効率よく使うため、またはセキュリティ上の理由から、ハフマン符号化した文字列を次のバイト境界までパディングを追加します。すなわち 0-7 ビットのパディングが文字列にあらわれます。

ハフマン符号化だけを考えるなら、必要なパディングよりも長いシンボルならどれでもパディングとして使うことができます。しかしながら HPACK のデザインは、ハフマン符号化した文字列をバイト単位で比較することを許しているのです。EOS シンボルのビット列をパディングとして使うことを要求することで、我々はハフマン符号化された文字列同士をバイト単位の比較で同一性を確認できることを保証するのです。これは多くのヘッダーはハフマン符号をデコードせずに解釈することができるということも意味するのです。

HTTP/1.1 を実装することなく HTTP/2 を実装できますか?

はい、ほとんどは可能です。

TLS 上の HTTP/2 (h2) では、http1.1 ALPN 識別子を実装しなければ、HTTP/1.1 の機能をサポートする必要はないでしょう。

TCP 上の HTTP/2 (h2c) については、最初のアップグレードリクエストを実装する必要があります。

"*" に対する OPTIONS リクエストや、"/" に対する HEAD リクエストを発行する必要がある h2c にのみ対応するクライアントは、安全であり構築が容易です。HTTP/2 のみの実装を期待するクライアントは、101 ステータスコードでない HTTP/1.1 レスポンスはエラーとして扱う必要があります。

h2c にのみ対応するサーバーは Upgrade ヘッダーフィールドを含むリクエストを、101 レスポンスと共に受け付けることができます。h2c のアップグレードトークンがないリクエストは、Upgrade ヘッダーフィールドを含む 505 (HTTP Version Not Supported) ステータスコードと共に拒否できます。HTTP/1.1 レスポンスの処理を望まないサーバーは、クライアントがアップグレードされた HTTP/2 コネクション上でリクエストを再施行することを促すために、コネクションプリフェイスの送信後に、ストリーム1を REFUSED_STREAM エラーコードと共に直ちに拒否すべきです。

5.3.2 の優先度の例は間違っていませんか?

いいえ。Stream B の重みは 4 で、Stream C の重みは 12 です。各ストリームが受け取る利用可能なリソースの割合を確認するには、全ての重みを合計 (16) し、各ストリームの重みを重みの合計で割ります。そのため、Stream B は 1/4 のリソースを受け取り、Stream C は 3/4 のリソースを受け取ります。仕様の状態にもあるように、Stream B は理想的には、Stream C に割り当てられたリソースの 1/3 を受け取ります。

HTTP/2 コネクションは、TCP_NODELAY が必要でしょうか?

はい、おそらく。単一のストリームを仕様して多くのデータをダウンロードするだけのクライアント実装であっても、最大の転送速度を得るために一部のパケットをピアに送信する必要があります。TCP_NODELAY を設定しなければ (Nagle アルゴリズムを許可していれば)、1つのパケットにマージすることを可能にするために、送信パケットはしばらくの間保持されるでしょう。

このようなパケットには、例えば、データを送信するために利用可能なウインドウが存在することをピアに知らせるためのパケットがあります。このパケットの送信を数ミリ秒 (またはそれ以上) 遅延させると、高速な接続に深刻な影響を与えます。

デプロイに関する質問

暗号化された HTTP/2 はどのようにデバッグしたらよいですか?

アプリケーションデータにアクセスする方法は多くありますが、(最新の開発版に含まれる) Wireshark プラグインと組み合わせて NSS Key Logging を使用するのが最も簡単でしょう。これは Firefox と Chrome の両方で動作します。

HTTP/2 サーバープッシュはどのように使えばよいですか?

HTTP/2 サーバープッシュは、リクエストを待つことなく、サーバーがクライアントにコンテンツを提供することを可能にします。これは、特にネットワークの往復時間のほとんどがリソースに費やす時間になるような、ネットワーク大きな帯域遅延積のコネクションにおいて、リソースの取得時間を改善できます。

リクエストの内容に基づいて変化するリソースをプッシュするのは適切ではありません。現在のところ、ブラウザは合致するリクエストをする必要がある場合 (RFC 7234 の4章を参照) にのみ、プッシュされたリクエストを使用します。

一部のキャッシュは、Vary ヘッダーフィールドに含まれている場合であっても、全てのリクエストヘッダーフィールドの変化を尊重しません。プッシュされたリクエストが受け入れられる可能性を最大化するために、コンテンツネゴシエーションは避けたほうが良いと言えます。accept-encoding ヘッダーフィールドに基づくコンテンツネゴシエーションは広くキャッシュにより尊重されますが、他のヘッダーフィールドも同じようにサポートされているとは限りません。